функция записи точного числа (логарифма) - PullRequest
2 голосов
/ 30 мая 2019

Поскольку логарифм основания 10 для 1000 равен 3, можно ожидать, что Math::log(1000, 10) вернет 3. Вместо этого он возвращает 2.9999999999999996.

Это связано с тем, что числа с плавающей точкой в ​​Ruby не являются точными числами, как обсуждалось, например, здесь :

Число с плавающей запятой не является точным представлением чисел, как указано в ruby документы

Объекты с плавающей точкой представляют неточные действительные числа, используя представление с плавающей точкой двойной точности в собственной архитектуре.

Это не ошибка ruby, поскольку поплавки могут быть представлены только фиксированным количество байтов и поэтому не может правильно хранить десятичные числа.

В качестве альтернативы вы можете использовать ruby ​​ Rational или BigDecimal

К сожалению, при вызове Math::log(BigDecimal('1000'), BigDecimal('10')) результат точно такой же. То же самое касается Math::log(Rational('1000'), Rational('10')). Существует также BigMath::log, который делает что-то совершенно другое .

Теперь главный вопрос: как мы можем вычислить логарифм 10 для основания 10, чтобы получить точный результат: 3?

Ответы [ 2 ]

1 голос
/ 30 мая 2019

Вы столкнулись с ограничением чисел с плавающей точкой здесь. Float s обычно имеют точность 15 десятичных знаков в Ruby , но значение 2.9999999999999996 показывает 16 десятичных знаков (ненадежной) точности.

Чтобы вернуться к достоверной точности, округлите до 15 знаков после запятой:

>> Math::log(1000, 10)
=> 2.9999999999999996
>> Math::log(1000, 10).round(15)
=> 3.0

Спецификация языка C только требует 10 значащих десятичных знаков для double, поэтому возможно, что реализация Ruby будет иметь Float s с менее чем 15 значительными десятичные разряды, но все же гораздо чаще можно увидеть здесь 15 значащих десятичных разрядов.

0 голосов
/ 30 мая 2019

Вы можете использовать изменение базовой формулы : если вы можете рассчитать журнал с базой d, но вам нужна база b, тогда log_b(n) = log_d(n) / log_d(b).Итак:

> BigMath.log(1000, 50) / BigMath.log(10, 50)
=> 0.3e1

Теперь давайте попробуем что-то, что требует большей точности:

> BigMath.log(999, 50) / BigMath.log(10, 50)
=> 0.2999565488225982308693534399304475375583359282738400141107276831709276456467950527020061473296516829369378125e1

Сравните это, скажем, с https://www.wolframalpha.com/input/?i=log_10+999

...