#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
недостаточно, поскольку оно целое).