Ответ 1
Это не имеет ничего общего с последней цифрой 5 и всем, что связано с преобразованием десятичного значения в значение с плавающей запятой с двойной точностью.
http://en.wikipedia.org/wiki/Double_precision_floating-point_format
В принципе, десятичное число должно быть представлено в ограниченном двоичном формате, который может приближать только определенные десятичные значения, что приводит к потере точности. Это может вызвать какое-то странное поведение, как вы видели.
Лучше всего объяснить это, показывая вам... Marshal.dump(1.025)
выгружает значение Float и показывает значение, немного близкое к тому, что оно на самом деле: 1.0249999999999999. 1.025.to_r
предоставит вам дробь, которая представляет двоичное значение. Вы можете использовать произвольно точную десятичную библиотеку BigDecimal для преобразования:
ruby-1.9.2-p180 :060 > (BigDecimal.new("2308094809027379.0") / BigDecimal.new("2251799813685248.0")).to_s('F')
=> "1.024999999999999911182158029987476766"
Когда определенные десятичные знаки преобразуются в этот "приблизительный" формат двоичных чисел, они будут представлены по-разному, возможно, более точно. Таким образом, вы могли заметить, что 1.085.round(2)
приводит к 1.09, как и следовало ожидать.
Это отсутствие точности с математикой с плавающей запятой означает, что она никогда, никогда не будет использовать значения с плавающей запятой для валютных расчетов или даже как временные контейнеры для денежных значений. Произвольные точные типы данных должны использоваться во все времена для чего-либо, связанного с деньгами.
Как бывший разработчик для чрезвычайно крупной финансовой компании, меня постоянно удивляло, как редко этот совет учитывается и насколько распространенным является использование поплавков или удваивается в финансовом программном обеспечении. Большинство программистов в этой отрасли, о которой я говорил, не знают о том, что плавающие и парные не должны хранить денежные ценности. Итак, не чувствуйте, что вы слишком за кривой, -)
TL;DR
Использовать BigDecimal: BigDecimal.new("1.025").round(2)
= > "1.03"