BigNumber.js вычисление показывает другое значение при выполнении того же вычисления в C # с использованием десятичного типа данных

#javascript #c# #arbitrary-precision #bignumber.js

#javascript #c# #произвольная точность #bignumber.js

Вопрос:

Я использовал BigNumber.js библиотека для высокоточных арифметических вычислений. Для поддержания более высокой точности я использую toFixed метод объекта Bignumber следующим образом:

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

Приведенный выше код выдает результат как 2999.99999999999998275 . Я попытался проверить этот результат вычисления в C #, используя decimal тип данных, потому что decimal имеет более высокую точность, чем double, но результат был другим на детальном уровне.

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

Это вычисление дает значения как 3000.0000000000000000000001 . Есть идеи, почему такие различия?

Комментарии:

1. BigNumber и C # decimal не совпадают, поэтому неудивительно, что они имеют разную точность

2. @Evk Разница обусловлена максимальной точностью? Но мой единственный вопрос — как мне проверить это вычисление большого числа

3. Например, bignumber.js имеет конфиг, и там есть опция DECIMAL_PLACES: «Максимальное количество десятичных знаков результатов операций, связанных с делением, т.е. операций деления, преобразования квадратного корня и основания, а также степенных операций с отрицательными показателями.». Значение по умолчанию 20, но вы можете его изменить. В то же время C # decimal имеет другие правила, в documentaiton указано, что он имеет точность 28-29 цифр (хотя это не то же самое, что и в приведенной выше конфигурации, но вы уже можете заметить разницу), и вы не можете это изменить. C # decimal не является произвольным числом точности, как bigjs.

4. Итак, для сравнения — вам также нужно произвольное число точности в C #, и настройте их одинаково, если это возможно. Я не знаю ни одного встроенного типа C # с такими свойствами (есть BigInteger , но это целое число, без дробей), но, возможно, есть библиотека третьей стороны. Или вы можете выяснить, как C # decimal точно представляет число, и попытаться сделать то же самое в bigjs, если это возможно.

5. @Evk Да, я могу видеть сходство сейчас, когда я изменил значение DECIMAL_PLACES по умолчанию на 28. Он действительно показывал значение как 3000.0000000000000000000000885 . Кроме того, глядя на ваше предложение, я мог бы поискать какую-нибудь другую стороннюю библиотеку на C # или альтернативный метод. На данный момент это решает мою цель.

Ответ №1:

Чтобы немного прояснить мои комментарии — BigNumber из JS — произвольное число точности. Это означает, что он может хранить произвольные большие и малые числа. Однако дробная часть не может иметь произвольную точность, поскольку многие числа имеют бесконечное десятичное разложение. Простые выражения, такие как 1 / 3 или sqrt(2) , содержат бесконечное количество цифр в дробной части. Для этого в bigjs есть параметр конфигурации, DECIMAL_PLACES определенный как:

Максимальное количество десятичных знаков результатов операций, включающих деление, т.Е. Операции деления, преобразования квадратного корня и основания, а также степенные операции с отрицательными показателями.

С другой стороны, C # decimal не является произвольным типом точности. Он имеет фиксированный размер и фиксированную точность 28-29 цифр (как указано в документации). Это число включает цифры как до, так и после точки.

Это означает, что если вы установите DECIMAL_PLACES значение 28 и разделите два числа с результатом меньше 1 — этот результат должен соответствовать C # decimal. Однако, как только вы умножите этот результат на некоторое большее число — они начнут расходиться. В BigJS по-прежнему будет 28 цифр после точки, но в C # decimal всего 28 цифр, поэтому, если результат равен, например, 10000., тогда количество точных цифр в дробной части равно 28-5 = 23, и они начнут расходиться.

Короче говоря, вам нужно найти стороннюю библиотеку для C #, которая предоставляет такое же дробное число произвольной точности ( BigInteger недостаточно, поскольку оно целое).