Проблема с точностью математических операций Ruby - PullRequest
1 голос
/ 23 сентября 2010

Знаете ли вы, как решить следующую проблему с математической точностью?

p RUBY_VERSION # => "1.9.1"
p 0.1%1 # => 0.1
p 1.1%1 # => 0.1
p 90.0%1 # => 0.0
p 90.1%1 # => 0.0999999999999943
p 900.1%1 # => 0.100000000000023

p RUBY_VERSION # => "1.9.2"
p 0.1%1 # => 0.1
p 1.1%1 # => 0.10000000000000009
p 90.0%1 # => 0.0
p 90.1%1 # => 0.09999999999999432
p 900.1%1 # => 0.10000000000002274

Ответы [ 3 ]

5 голосов
/ 23 сентября 2010

Большое десятичное число


Как сказал человек ;

Для сжатия бесконечного числа действительных чисел в конечное число бит требуется приблизительное представление.


Однако я добился большого успеха, используя класс BigDecimal .Чтобы процитировать его вступление

Ruby предоставляет встроенную поддержку целочисленной арифметики произвольной точности.Например:

42 ** 13 -> 1265437718438866624512

BigDecimal предоставляет аналогичную поддержку для очень больших или очень точных чисел с плавающей запятой.


Возьмем один из ваших примеров;

>> x = BigDecimal.new('900.1')
=> #<BigDecimal:101113be8,'0.9001E3',8(8)>
>> x % 1
=> #<BigDecimal:10110b498,'0.1E0',4(16)>
>> y = x % 1
=> #<BigDecimal:101104760,'0.1E0',4(16)>
>> y.to_s
=> "0.1E0"
>> y.to_f
=> 0.1


Как видите, обеспечение достойной точности возможно, но требует немного усилий.

2 голосов
/ 23 сентября 2010

Это верно для всех компьютерных языков, не только для Ruby.Это функция представления чисел с плавающей запятой на двоичных компьютерах:

Что должен знать каждый компьютерный специалист об арифметике с плавающей запятой

1 голос
/ 23 сентября 2010

Запись 0.1 в число с плавающей запятой всегда приведет к ошибкам округления. Если вы хотите «точное» десятичное представление, вы должны использовать тип Decimal .

...