1

I have been using BigNumber.js library for high precision arithmetic calculation. To maintain higher precision I am using toFixed method of the Bignumber object like this:

(new BigNumber(6000 )).minus(9006000).div(9006000).times(4503000 ).plus(4503000 ).toFixed()

The above code gives result as 2999.99999999999998275. I tried validating this calculation result in C# using decimal data type because decimal has higher precision than double but the result was different at granular level.

decimal rg1 = 6000m;
decimal lastSavedRG1 = 9006000m;
decimal lastsavedrefinedgoalMonthly1 = 4503000m;
decimal cal1 = (lastsavedrefinedgoalMonthly1 + (lastsavedrefinedgoalMonthly1 * ((rg1 - lastSavedRG1) / lastSavedRG1)));

This calculation gives values as 3000.0000000000000000000001. Any idea why such differences ?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
nraina
  • 324
  • 2
  • 20
  • BigNumber and C# decimal are not the same, so no surprise they have different precisions – Evk Nov 10 '20 at 15:34
  • @Evk Is the difference due to maximum precision ?But my only query is how would I validate this big number calculation – nraina Nov 11 '20 at 05:48
  • 1
    For example, bignumber.js has a config, and there is an option DECIMAL_PLACES: "The maximum number of decimal places of the results of operations involving division, i.e. division, square root and base conversion operations, and power operations with negative exponents.". Default value 20, but you can change it. At the same time, C# decimal has another rules, documentaiton states that it has 28-29 digits precision (though it's not the same as above config, but you already can note the difference), and you cannot change that. C# decimal is not arbitrary precision number like bigjs is. – Evk Nov 11 '20 at 14:16
  • So to compare - you need arbitrary precision number in C# too, and configure them identically, if possible. I'm not aware of any built-in C# type with such properties (there is BigInteger, but it's well, integer, no fractions), but maybe there is trird party library. Or you can figure out how C# decimal exactly represents a number and try to do the same in bigjs, if possible. – Evk Nov 11 '20 at 14:18
  • @Evk Yes I am able to see the similarity now when i changed the default of DECIMAL_PLACES to 28. It did show the value as `3000.0000000000000000000000885`. Also, looking at your suggestion I might seek some other third party lib at C# or alternate method. As of it does solve my purpose. – nraina Nov 11 '20 at 14:50

1 Answers1

1

To clarify my comments a bit - BigNumber from JS is arbitrary precision number. That means it can store arbitrary big and small numbers. However, fractional part cannot have arbitrary precision, because many numbers have infinite decimal expansion. Simple expressions like 1 / 3 or sqrt(2) have infinite number of digits in fractional part. For that, there is configuration option in bigjs - DECIMAL_PLACES defined as:

The maximum number of decimal places of the results of operations involving division, i.e. division, square root and base conversion operations, and power operations with negative exponents.

C# decimal on the other hand is not arbitrary precision type. It has fixed size and fixed precision of 28-29 digits (as stated in documentation). This number includes digits both before and after the dot.

That means, if you set DECIMAL_PLACES to 28 and divide two numbers with the result of less than 1 - that result should agree with C# decimal. However, as soon as you multiply that result by some bigger number - they will start to disagree. BigJS will still have 28 digits after the dot, but C# decimal has 28 digits total, so if the result is, for example, 10000., then number of precise digits in fractional part is 28-5=23, and they will start to disagree.

In short - you need to find third party library for C# which provides the same fractional arbitrary precision number (BigInteger does not suffice, since it's integer).

Evk
  • 98,527
  • 8
  • 141
  • 191