Почему этот код 7.30 - 7.20
in ruby возвращает 0.0999999999999996
, а не 0.10
?Арифметика в рубине
Но, если я напишу 7.30 - 7.16
, например, все будет в порядке, я получу 0.14
.
В чем проблема, и как я могу ее решить?
Почему этот код 7.30 - 7.20
in ruby возвращает 0.0999999999999996
, а не 0.10
?Арифметика в рубине
Но, если я напишу 7.30 - 7.16
, например, все будет в порядке, я получу 0.14
.
В чем проблема, и как я могу ее решить?
Это распространенная ошибка в том, как числа чисел с плавающей точкой представлены в памяти.
Используйте BigDecimal, если вам нужны точные результаты.
result=BigDecimal.new("7.3")-BigDecimal("7.2")
puts "%2.2f" % result
Об этом можно говорить довольно хорошо: http://whynotwiki.com/Ruby_/_Numbers –
Обратите внимание, что BigDecimal дает только точные результаты, если число имеет конечное число цифр в основание 10. – sepp2k
http://floating-point-gui.de/ –
Проблема в том, что floating point is inaccurate. Вы можете решить это с помощью Rational, BigDecimal или просто простых целых чисел (например, если вы хотите хранить деньги, вы можете сохранить количество центов как int вместо количества долларов в качестве float).
BigDecimal может точно хранить любое число с конечным числом цифр в базе 10 и номерами раундов, которые не имеют (так что три трети не являются целыми).
Rational может точно хранить любое рациональное число и не может хранить иррациональные числа вообще.
Поскольку вы выполняете математику с плавающей запятой, возвращаемое число - это то, что ваш компьютер использует для точности.
Если вам нужен более близкий ответ, с заданной точностью, просто несколькими поплавками (например, на 100), преобразуйте его в int, выполните математику и разделите.
Есть и другие решения, но я считаю, что это самый простой, поскольку округление всегда кажется мне немного неудобным.
Это было предложено до сюда, вы можете захотеть взглянуть на некоторые из ответов приведены выше, такие, как этот: Dealing with accuracy problems in floating-point numbers
Проблема в том, что некоторые номера мы можем легко написать в десятичном формате не имеют точного представления в определенном формате с плавающей запятой, реализуемом текущим оборудованием. Случайный способ заявить об этом состоит в том, что все целые числа, но не все фракции, потому что мы обычно храним эту долю с помощью показателя 2**e
. Итак, у вас есть 3 варианта:
Завершите работу надлежащим образом. Неограниченный результат всегда действительно очень близок, поэтому округленный результат неизменно «совершенен». Это то, что делает Javascript, и многие люди даже не понимают, что JS делает все в плавающей точке.
Использовать арифметику с фиксированной точкой. Ruby действительно делает это очень легким; это один из единственных языков, который плавно переходит к классу Bignum из Fixnum, поскольку числа становятся больше.
Используйте класс, который предназначен для решения этой проблемы, как BigDecimal
Чтобы посмотреть на проблему более подробно, мы можем попытаться представить ваш «7,3» в двоичном коде. 7 часть легко, 111, но как мы это делаем .3? 111,1 составляет 7,5, слишком большой, 111,01 составляет 7,25, приближаясь.Оказывается, 111.010011 - это «следующее ближайшее меньшее число», 7.296875, и когда мы пытаемся заполнить отсутствующий .003125, в конце концов мы узнаем, что это просто 111.010011001100110011 ... навсегда, не представляемый в нашей выбранной кодировке в конечной битовой строке ,
Интересно отметить, что число, которое имеет несколько десятичных знаков в одной базе, обычно может иметь очень большое число десятичных знаков в другом. Например, для вычисления 1/3 (= 0.3333 ...) в базе 10 требуется бесконечное число десятичных знаков, но только одно десятичное число в базе 3. Аналогично, для выражения числа 1/10 требуется много десятичных знаков (= 0,1) в базе 2.
Право. Это верно независимо от языка - Java, Ruby, C# все «страдают» от этого. Это связано с выбором бинарной логики и нашего способа представления чисел с плавающей запятой. – duffymo