javascriptc#arbitrary-precisionbignumber.js

BigNumber.js calculation shows different value when done same calculation in C# using decimal datatype


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 ?


Solution

  • 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).