Skip to content

Commit dfdef5e

Browse files
authored
feat(div): add MustDiv (#44)
1 parent 3259bfe commit dfdef5e

File tree

3 files changed

+242
-0
lines changed

3 files changed

+242
-0
lines changed

decimal.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,16 @@ func (d Decimal) Div(e Decimal) (Decimal, error) {
570570
return newDecimal(neg, bintFromBigInt(dBig), defaultPrec), nil
571571
}
572572

573+
// MustDiv similar to Div, but panics instead of returning error
574+
func (d Decimal) MustDiv(e Decimal) Decimal {
575+
v, err := d.Div(e)
576+
if err != nil {
577+
panic(err)
578+
}
579+
580+
return v
581+
}
582+
573583
func tryDivU128(d, e Decimal, neg bool) (Decimal, error) {
574584
if d.coef.overflow() || e.coef.overflow() {
575585
return Decimal{}, errOverflow
@@ -652,6 +662,16 @@ func (d Decimal) QuoRem(e Decimal) (Decimal, Decimal, error) {
652662
return q, r, nil
653663
}
654664

665+
// MustQuoRem similar to QuoRem, but panics instead of returning error
666+
func (d Decimal) MustQuoRem(e Decimal) (Decimal, Decimal) {
667+
q, r, err := d.QuoRem(e)
668+
if err != nil {
669+
panic(err)
670+
}
671+
672+
return q, r
673+
}
674+
655675
func tryQuoRemU128(d, e Decimal) (Decimal, Decimal, error) {
656676
if d.coef.overflow() || e.coef.overflow() {
657677
return Decimal{}, Decimal{}, errOverflow
@@ -696,6 +716,16 @@ func (d Decimal) Mod(e Decimal) (Decimal, error) {
696716
return r, err
697717
}
698718

719+
// MustMod similar to Mod, but panics instead of returning error
720+
func (d Decimal) MustMod(e Decimal) Decimal {
721+
_, r, err := d.QuoRem(e)
722+
if err != nil {
723+
panic(err)
724+
}
725+
726+
return r
727+
}
728+
699729
// Prec returns decimal precision as an integer
700730
func (d Decimal) Prec() int {
701731
return int(d.prec)

decimal_test.go

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,99 @@ func TestDiv(t *testing.T) {
961961
}
962962
}
963963

964+
func TestMustDiv(t *testing.T) {
965+
testcases := []struct {
966+
a, b string
967+
overflow bool
968+
wantErr error
969+
}{
970+
{"22773757910726981402256170801141121114", "811656739243220271.159", false, nil},
971+
{"22773757910726981402256170801141121024", "2277375793122336353220649475.264577813", false, nil},
972+
{"2345678901234567899", "1234567890123456789.1234567890123456789", false, nil},
973+
{"123456.123", "8796093022208", false, nil},
974+
{"1844674407370955161.5999999999", "18446744073709551616", false, nil},
975+
{"1000000000000", "0.0000001", false, nil},
976+
{"479615345916448342049", "1494.186269970473681015", false, nil},
977+
{"123456.1234567890123456789", "234567.1234567890123456789", false, nil},
978+
{"123456.1234567890123456789", "1", false, nil},
979+
{"-123456.1234567890123456789", "234567.1234567890123456789", false, nil},
980+
{"123456.1234567890123456789", "-234567.1234567890123456789", false, nil},
981+
{"-123456.1234567890123456789", "-234567.1234567890123456789", false, nil},
982+
{"9999999999999999999", "1.0001", false, nil},
983+
{"-9999999999999999999.9999999999999999999", "9999999999999999999", false, nil},
984+
{"1234567890123456789", "1", false, nil},
985+
{"1234567890123456789", "2", false, nil},
986+
{"123456789012345678.9", "0.1", false, nil},
987+
{"1111111111111", "1111.123456789123456789", false, nil},
988+
{"123456789", "1.1234567890123456789", false, nil},
989+
{"0.1234567890123456789", "0.04586201546101", false, nil},
990+
{"1", "1111.123456789123456789", false, nil},
991+
{"1", "1.123456789123456789", false, nil},
992+
{"1", "2", false, nil},
993+
{"1", "3", false, nil},
994+
{"1", "4", false, nil},
995+
{"1", "5", false, nil},
996+
{"1234567890123456789.1234567890123456879", "1111.1789", false, nil},
997+
{"123456789123456789.123456789", "3.123456789", false, nil},
998+
{"123456789123456789.123456789", "3", false, nil},
999+
{"9999999999999999999", "1234567890123456789.1234567890123456879", false, nil},
1000+
{"9999999999999999999.999999999999999999", "1000000000000000000.1234567890123456789", false, nil},
1001+
{"999999999999999999", "0.100000000000001", false, nil},
1002+
{"123456789123456789.123456789", "0", false, ErrDivideByZero},
1003+
{"1234567890123456789.1234567890123456789", "0.0000000000000000002", true, nil},
1004+
{"1234567890123456789.1234567890123456789", "0.000000001", true, nil},
1005+
{"1000000000000000000000000.1234567890123456789", "-100000000000000000000", true, nil},
1006+
{"1234567890123456789012345678901234567890.1234567890123456789", "1234567890123456789012345678901234567890.1234567890123456789", true, nil},
1007+
{"1234567890123456789012345678901234567890.1234567890123456789", "-1234567890123456789012345678901234567890.1234567890123456789", true, nil},
1008+
{"-1234567890123456789012345678901234567890.1234567890123456789", "1234567890123456789012345678901234567890.1234567890123456789", true, nil},
1009+
{"-1234567890123456789012345678901234567890.1234567890123456789", "-1234567890123456789012345678901234567890.1234567890123456789", true, nil},
1010+
}
1011+
1012+
for _, tc := range testcases {
1013+
t.Run(tc.a+"/"+tc.b, func(t *testing.T) {
1014+
a, err := Parse(tc.a)
1015+
require.NoError(t, err)
1016+
1017+
b, err := Parse(tc.b)
1018+
require.NoError(t, err)
1019+
1020+
aStr := a.String()
1021+
bStr := b.String()
1022+
1023+
if tc.wantErr != nil {
1024+
require.PanicsWithError(t, tc.wantErr.Error(), func() {
1025+
_ = a.MustDiv(b)
1026+
})
1027+
return
1028+
}
1029+
1030+
c := a.MustDiv(b)
1031+
assertOverflow(t, c, tc.overflow)
1032+
1033+
// make sure a and b are immutable
1034+
require.Equal(t, aStr, a.String())
1035+
require.Equal(t, bStr, b.String())
1036+
1037+
// compare with shopspring/decimal
1038+
aa := decimal.RequireFromString(tc.a)
1039+
bb := decimal.RequireFromString(tc.b)
1040+
1041+
prec := int32(c.Prec())
1042+
cc := aa.DivRound(bb, 28).Truncate(prec)
1043+
1044+
// sometimes shopspring/decimal does rounding differently
1045+
// e.g. 0.099999999999999 -> 0.1
1046+
// so to check the result, we can check the difference
1047+
// between our result and shopspring/decimal result
1048+
// valid result should be less than or equal to 1e-19, which is our smallest unit
1049+
d := MustParse(cc.String())
1050+
e := c.Sub(d)
1051+
1052+
require.LessOrEqual(t, e.Abs().Cmp(oneUnit), 0, "expected %s, got %s", cc.String(), c.String())
1053+
})
1054+
}
1055+
}
1056+
9641057
func TestDivWithCustomPrecision(t *testing.T) {
9651058
SetDefaultPrecision(14)
9661059
defer SetDefaultPrecision(maxPrec)
@@ -1175,6 +1268,58 @@ func TestQuoRem(t *testing.T) {
11751268
}
11761269
}
11771270

1271+
func TestMustQuoRem(t *testing.T) {
1272+
testcases := []struct {
1273+
a, b string
1274+
q, r Decimal
1275+
wantErr error
1276+
}{
1277+
{"22773757910726981402256170801141121024", "-20715693594775826464.768", MustParse("-1099348076690522519"), MustParse("3006819284014656913.408"), nil},
1278+
{"12345678901234567890123456.1234567890123456789", "123456789012345678900", MustParse("100000"), MustParse("123456.1234567890123456789"), nil},
1279+
{"12345678901234567890123", "1.1234567890123456789", MustParse("10989010900978142640527"), MustParse("0.4794672386555312197"), nil},
1280+
{"1.1234567890123456789", "123456789012345678900", MustParse("0"), MustParse("1.1234567890123456789"), nil},
1281+
{"12345678901234567890.123456789", "1.1234567890123456789", MustParse("10989010900978142640"), MustParse("0.592997984048161704"), nil},
1282+
{"123456789.1234567890123456789", "123.123456789", MustParse("1002707"), MustParse("37.1369289660123456789"), nil},
1283+
{"1234567890123456789", "1", MustParse("1234567890123456789"), Zero, nil},
1284+
{"11.234", "1.12", MustParse("10"), MustParse("0.034"), nil},
1285+
{"-11.234", "1.12", MustParse("-10"), MustParse("-0.034"), nil},
1286+
{"11.234", "-1.12", MustParse("-10"), MustParse("0.034"), nil},
1287+
{"-11.234", "-1.12", MustParse("10"), MustParse("-0.034"), nil},
1288+
{"123.456", "1.123", MustParse("109"), MustParse("1.049"), nil},
1289+
{"-11.234", "0", MustParse("10"), MustParse("-0.034"), ErrDivideByZero},
1290+
}
1291+
1292+
for _, tc := range testcases {
1293+
t.Run(fmt.Sprintf("%s.QuoRem(%s)", tc.a, tc.b), func(t *testing.T) {
1294+
a, err := Parse(tc.a)
1295+
require.NoError(t, err)
1296+
1297+
b, err := Parse(tc.b)
1298+
require.NoError(t, err)
1299+
1300+
if tc.wantErr != nil {
1301+
require.PanicsWithError(t, tc.wantErr.Error(), func() {
1302+
_, _ = a.MustQuoRem(b)
1303+
})
1304+
return
1305+
}
1306+
1307+
q, r := a.MustQuoRem(b)
1308+
1309+
require.Equal(t, tc.q.String(), q.String())
1310+
require.Equal(t, tc.r.String(), r.String())
1311+
1312+
// compare with shopspring/decimal
1313+
aa := decimal.RequireFromString(tc.a)
1314+
bb := decimal.RequireFromString(tc.b)
1315+
1316+
qq, rr := aa.QuoRem(bb, 0)
1317+
require.Equal(t, qq.String(), q.String())
1318+
require.Equal(t, rr.String(), r.String())
1319+
})
1320+
}
1321+
}
1322+
11781323
func TestMod(t *testing.T) {
11791324
testcases := []struct {
11801325
a, b string
@@ -1222,6 +1367,55 @@ func TestMod(t *testing.T) {
12221367
}
12231368
}
12241369

1370+
func TestMustMod(t *testing.T) {
1371+
testcases := []struct {
1372+
a, b string
1373+
r Decimal
1374+
wantErr error
1375+
}{
1376+
{"12345678901234567890123456.1234567890123456789", "123456789012345678900", MustParse("123456.1234567890123456789"), nil},
1377+
{"12345678901234567890123", "1.1234567890123456789", MustParse("0.4794672386555312197"), nil},
1378+
{"1.1234567890123456789", "123456789012345678900", MustParse("1.1234567890123456789"), nil},
1379+
{"12345678901234567890.123456789", "1.1234567890123456789", MustParse("0.592997984048161704"), nil},
1380+
{"123456789.1234567890123456789", "123.123456789", MustParse("37.1369289660123456789"), nil},
1381+
{"1234567890123456789", "1", Zero, nil},
1382+
{"11.234", "1.12", MustParse("0.034"), nil},
1383+
{"-11.234", "1.12", MustParse("-0.034"), nil},
1384+
{"11.234", "-1.12", MustParse("0.034"), nil},
1385+
{"-11.234", "-1.12", MustParse("-0.034"), nil},
1386+
{"123.456", "1.123", MustParse("1.049"), nil},
1387+
{"-11.234", "0", MustParse("-0.034"), ErrDivideByZero},
1388+
}
1389+
1390+
for _, tc := range testcases {
1391+
t.Run(fmt.Sprintf("%s.QuoRem(%s)", tc.a, tc.b), func(t *testing.T) {
1392+
a, err := Parse(tc.a)
1393+
require.NoError(t, err)
1394+
1395+
b, err := Parse(tc.b)
1396+
require.NoError(t, err)
1397+
1398+
if tc.wantErr != nil {
1399+
require.PanicsWithError(t, tc.wantErr.Error(), func() {
1400+
_ = a.MustMod(b)
1401+
})
1402+
return
1403+
}
1404+
1405+
r := a.MustMod(b)
1406+
1407+
require.Equal(t, tc.r.String(), r.String())
1408+
1409+
// compare with shopspring/decimal
1410+
aa := decimal.RequireFromString(tc.a)
1411+
bb := decimal.RequireFromString(tc.b)
1412+
1413+
rr := aa.Mod(bb)
1414+
require.Equal(t, rr.String(), r.String())
1415+
})
1416+
}
1417+
}
1418+
12251419
func TestCmp(t *testing.T) {
12261420
testcases := []struct {
12271421
a, b string

doc_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@ func ExampleDecimal_Div() {
214214
// 0 can't divide by zero
215215
}
216216

217+
func ExampleDecimal_MustDiv() {
218+
fmt.Println(MustParse("1.23").MustDiv(MustParse("4.12475")))
219+
// Output:
220+
// 0.2981998909024789381
221+
}
222+
217223
func ExampleDecimal_Div64() {
218224
fmt.Println(MustParse("1.23").Div64(4))
219225
fmt.Println(MustParse("1.23").Div64(0))
@@ -230,6 +236,12 @@ func ExampleDecimal_QuoRem() {
230236
// 0 0 can't divide by zero
231237
}
232238

239+
func ExampleDecimal_MustQuoRem() {
240+
fmt.Println(MustParse("1.23").MustQuoRem(MustParse("0.5")))
241+
// Output:
242+
// 2 0.23
243+
}
244+
233245
func ExampleDecimal_Mod() {
234246
fmt.Println(MustParse("1.23").Mod(MustParse("0.5")))
235247
fmt.Println(MustParse("1.23").Mod(MustParse("0")))
@@ -238,6 +250,12 @@ func ExampleDecimal_Mod() {
238250
// 0 can't divide by zero
239251
}
240252

253+
func ExampleDecimal_MustMod() {
254+
fmt.Println(MustParse("1.23").MustMod(MustParse("0.5")))
255+
// Output:
256+
// 0.23
257+
}
258+
241259
func ExampleDecimal_Sub() {
242260
a := MustParse("1.23")
243261
b := MustParse("4.12475")

0 commit comments

Comments
 (0)