Closed tom-sherman closed 4 years ago
This does not seem to be a problem with big.js.
Probably similar bug with subtraction:
const result1 = a.sub(b).sub(c);
const result2 = a.sub(b.add(c));
Gives different results:
61151.88334586265491493
39165.25929059911
15132.518521452032
=
6854.105533811512915
6854.1055338115129149
----------------
46749.4651970984415455
96478.89913780178
89024.39114386331
=
-138753.82508456664846
-138753.82508456664845
----------------
54475.5665251096347428
2185.5827202641453
57825.85036833445
=
-5535.866563488960557
-5535.8665634889605572
----------------
58992.9583753479768395
33080.30873264703
73094.27562413673
=
-47181.62598143578316
-47181.625981435783161
----------------
64844.5226497100850571
11926.844436415584
55366.61233115836
=
-2448.934117863858943
-2448.9341178638589429
----------------
78633.3759187694437864
61349.60896677592
24037.334341935868
=
-6753.567389942344214
-6753.5673899423442136
----------------
23262.6238587170458838
9113.905513593034
7502.578484250666
=
6646.139860873345884
6646.1398608733458838
And the same bug with multiplication:
const result1 = a.mul(b).mul(c);
const result2 = a.mul(b.mul(c));
Sometimes very different results:
54589.4651442717259757
14531.661735889224
87000.43426094622
=
69015325326942.290179
69015325326942.290177
----------------
52048.32741142384580627
53639.76666863257
23092.74059529074
=
64471701941503.353832
64471701941503.353829
----------------
33399.89694640863159
30781.520873727917
24155.741512409313
=
24834508791380.318002
24834508791380.318
----------------
3451.11469792955847387
34499.40876089024
74401.5767897021
=
8858357133173.036061
8858357133173.0360608
And division is affected as well:
const result1 = a.div(b).div(c);
const result2 = a.div(b.mul(c));
Results:
49071.7151697405872294
19651.555584921844
56327.54692030375
=
0.000044331606098322916993
0.00004433160609832291699
----------------
34230.9480468589585105
16920.466962595303
34158.96473380873
=
0.00005922456548766828347
0.000059224565487668283468
----------------
75805.3619716876658181
14663.844716427076
78686.83897169911
=
0.000065697670970978308659
0.000065697670970978308656
----------------
61983.5809415613374257
16601.813314653402
7057.458466598976
=
0.00052902087064047293051
0.00052902087064047293053
----------------
59362.35693026017511214
29587.34934146463
46701.80233764018
=
0.000042960708493808559056
0.000042960708493808559058
----------------
64187.7243637776484876
16905.705182181995
72720.60253411996
=
0.000052210904779655426607
0.000052210904779655426609
----------------
91187.7781421704394917
40380.80558308221
41165.87623742567
=
0.000054856019542917490185
0.000054856019542917490183
----------------
57233.88444065540565098
80262.92293133863
1279.4662545472236
=
0.00055732614240645836888
0.0005573261424064583689
@i-fail Subtraction and division are not associative so I think you would expect different results with those examples. Not entirely sure of your test cases though.
Multiplication is associcative though so I would assume those are bugs.
Subtraction is not associative
Well, a-b-c should have the same result as a-(b+c). This is an arbitrary-precision library, isn't it?
This argument would be correct for division, which can require infinite precision.
Ah, I didn't read your examples correctly, I thought you were doing a-b-c == a-(b-c)
There's no bug here, just wasted time and effort, and quite a few people seemingly not understanding the basics of how the library works.
Operations are rounded to the number of significant digits specified by the Decimal.precision
setting, which is 20 by default.
The mathematical result of a.add(b)
is "-12.2087444884059531363"
which is 21 digits long, so it gets rounded to "-12.208744488405953136"
.
Just try putting, for example,
Decimal.precison = 25;
after the import, and the results will be as expected.
It is best to always specify the precision explicitly even if you are using the default value.
This is an arbitrary-precision library, isn't it?
I guess the misunderstanding is that "arbitrary precision" does not mean "infinite precision". Though you can specify how many digits you want to use with calculations in decimal.js
, you're still working with floating point and limited precision, and hence have round-off errors when for example doing divisions such as 1/3
(which cannot be represented with a limited number of digits).
In order to understand what bignumber.js can and can't do, it's important to understand the limitations of floating point calculations.
Fiddle: https://jsfiddle.net/es9pun76/3/
I originally found this bug while using decimal.js-light, I've raised it there too: https://github.com/MikeMcl/decimal.js-light/issues/13