BigNumber.js 在 C# 中使用十进制数据类型进行相同计算时,计算显示不同的值

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

我一直在使用BigNumber.js库进行高精度算术计算。为了保持更高的精度,我使用 Bignumber 对象的 toFixed 方法,如下所示:

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

以上代码给出的结果为2999.99999999999998275。我尝试使用 decimal 数据类型在 C# 中验证此计算结果,因为 decimal 比 double 具有更高的精度,但结果在粒度级别不同。

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

此计算给出的值为 3000.0000000000000000000001。知道为什么会有这样的差异吗?

澄清一下我的评论 - 来自 JS 的 BigNumber 是任意精度数字。这意味着它可以存储任意大小的数字。但是,小数部分不能有任意精度,因为很多数字有无限小数展开。 1 / 3sqrt(2) 等简单表达式的小数部分有无限个数字。为此,bigjs 中有配置选项 - 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.

另一方面,C# decimal 不是任意精度类型。它具有 28-29 位的固定大小和固定精度(如文档中所述)。此数字包括点前后的数字。

这意味着,如果您将 DECIMAL_PLACES 设置为 28 并将两个数字相除且结果小于 1 - 该结果应符合 C# 十进制。然而,一旦你将该结果乘以某个更大的数字——他们就会开始不同意。 BigJS 的点后面还有 28 位,但是 C# decimal 总共有 28 位,所以如果结果是,比如 10000.,那么小数部分的精确位数是 28-5=23,他们会开始不同意。

简而言之 - 您需要找到 C# 的第三方库,它提供相同的小数任意精度数(BigInteger 不够,因为它是整数)。