У меня есть калькулятор времени, который достаточно хорошо работает уже несколько лет. Одна вещь, которая всегда беспокоила меня, заключалась в том, что если использовать дробные секунды, результаты станут жертвой «ошибок» с плавающей запятой. Итак, недавно я переключился на использование этой библиотеки BigDecimal.
Теперь я получаю математические ошибки. Вот упрощенный тестовый пример из отчета об ошибке, который я получил сегодня: 27436 / 30418
возвращает 1
вместо ожидаемого 0.9019659412190151
.
Чтобы проиллюстрировать мою проблему, вот сеанс консоли Javascript в Chrome:
> first = 27436
27436
> second = 30418
30418
> first / second
0.9019659412190151 // expected result, but using JS numbers, not BigDecimals
> firstB = new BigDecimal(first.toString())
o
> secondB = new BigDecimal(second.toString())
o
> firstB / secondB
0.9019659412190151 // this is a JS number, not a BigDecimal, so it's susceptible to the problems associated with floating-point.
> firstB.divide(secondB)
o // BigDecimal object
> firstB.divide(secondB).toString()
"1" // huh? Why 1?
> firstB.divideInteger(secondB).toString()
"0"
Как видите, метод divide()
не дает ожидаемого результата. Что мне нужно сделать по-другому?
Обновлять
Вот еще некоторые подробности, в ответ на комментарии.
Во-первых, несколько человек предположили, что использование BigDecimal было излишним. Возможно, но я думаю, что прежде чем принимать такое решение, необходимо больше деталей. Это приложение представляет собой калькулятор времени. в BigDecimal. Во-первых, поскольку это калькулятор, важно показать пользователю правильный ответ. Если пользователь вводит 0.1 s + 0.2 s
, он ожидает, что ответ будет 0.3 s
, а не ответ, который ему покажет Javascript (0.30000000000000004
).
Я действительно не хочу ограничивать точность сверх того, что я могу использовать в JS, чтобы я мог использовать целые числа, потому что я не знаю максимальной точности, необходимой моим пользователям. Я думаю, что большинство никогда не используют доли секунды, но, судя по электронной почте, которую я получил, некоторые используют. В настоящее время я храню все время внутри в секундах.
Кто-то предложил мне хранить числа в виде точных дробей. К сожалению, я не знаю, что это значит. Возможно, это потому, что я не слишком хорошо разбираюсь в математике. Я недостаточно знаю, чтобы собрать собственную математическую библиотеку; вот почему я использую BigDecimal. Он существует уже давно, поэтому я не решаюсь сказать, что моя проблема связана с ошибкой в BigDecimal. Я подозреваю, что это ошибка в том, как я его использую.
Наконец, я не привязан конкретно к BigDecimal. Я открыт для других предложений, при условии, что я могу использовать их с моими недостаточными математическими способностями.