Float

Float в Ruby — это класс, представляющий вещественные числа (дробные числа с плавающей точкой двойной точности). Они записываются с десятичной точкой (например, 3.14) и используются для вычислений, требующих точности.

Float могут иметь проблемы с точностью при десятичных вычислениях из-за двоичного представления. Ruby всегда преобразует числа с плавающей точкой из десятичного формата в двоичный и наоборот. При преобразовании десятичного числа в двоичное, результирующее двоичное число может быть бесконечным. Математически это всё нормально. Но на практике у компьютера нет бесконечной памяти, поэтому Ruby должен в какой-то момент обрезать бесконечное число, иначе оно заполнит всю память компьютера и станет бесполезным. Этот механизм округления чисел и приводит к ошибке округления.

>> 0.1 + 0.05 == 0.15
=> false

>> 0.1 + 0.05
=> 0.15000000000000002

>> sprintf("%0.50f", 0.10 + 0.05)
=> "0.15000000000000002220446049250313080847263336181641"

>> sprintf("%0.50f", 0.10)
=> "0.10000000000000000555111512312578270211815834045410"
>> sprintf("%0.50f", 0.05)
=> "0.05000000000000000277555756156289135105907917022705"

Как видно из примера выше, Ruby обрезает значение Float при преобразовании полученной бесконечности при постановке и извлечения из памяти.

Из этого возникает два вопроса - как сравнивать два значения Float? Как обеспечить точность при работе со значениями, где она критически важна (к примеру, с деньгами)?

Что касается сравнения, один из способов это использовать Delta Number. Это число можно рассматривать как показатель погрешности округления. Например, разница для операции 0,10 + 0,05 составляет приблизительно 0,0000000000000001. Разница должна быть больше или равна абсолютному значению результата вычитания ожидаемого и фактического значений.
То есть можно использовать следующий метод -

def assert_in_delta(exp, act, delta)
n = (exp - act).abs
delta >= n
end

assert_in_delta(0.15, (0.10 + 0.05), 0.0000000000000001)
 => true