Последовательное округление плавающих точек в Ruby - PullRequest
2 голосов
/ 23 декабря 2009

Я понимаю, что из-за неточного представления чисел с плавающей запятой, следующий код "кажется" непоследовательным.

"%.1f" % 1.14 # => 1.1
"%.1f" % 1.15 # => 1.1
"%.1f" % 1.16 # => 1.2
"%.0f" % 1.4 # => 1
"%.0f" % 1.5 # => 2
"%.0f" % 1.6 # => 2

Однако, есть ли простой способ сделать последовательное округление с плавающей запятой на 5? Одним из способов может быть явное манипулирование строками. Есть ли более простой способ или существующая библиотека?

Ответы [ 4 ]

5 голосов
/ 23 декабря 2009

Если вам нужна десятичная точность, используйте BigDecimal вместо числа с плавающей запятой.

Редактировать : Вам нужно будет вручную округлить число до желаемой длины, прежде чем передать его в %, в противном случае оно будет преобразовано в обычный плавающий перед округлением.

"%.1f" % BigDecimal('1.15').round(1) => "1.2"
"%.0f" % BigDecimal('1.5').round(0) => "2"
2 голосов
/ 23 декабря 2009

Просто добавьте крошечное пертурбацию, чтобы вещи с плавающей точкой чуть меньше 0,5 стали чуть более.

Например,

x = 1.15
"%.1f" % (1.000001*x)  # include correction for imprecise floating-point.

этого будет достаточно для решения проблем с форматированием, но вряд ли это приведет к соответствующей ошибке.

также: очевидное продолжение моего более раннего вопроса здесь , что хорошо, но включено для полноты.

1 голос
/ 23 декабря 2009

Функция roundthis() в этом примере показывает, как округлять числа контролируемым, последовательным способом. Обратите внимание на небольшое значение выдумки. Попробуйте запустить этот пример без помадки, чтобы увидеть, что происходит.

def roundthis(x, m)
    return (x/m+0.50001).floor*m
end

for x in [1.14, 1.15, 1.16]
    print "#{x}   #{roundthis(x, 0.1)}  \n"
end

for x in [1.4, 1.5, 1.6]
    print "#{x}   #{roundthis(x, 1.0)}  \n"
end

Это, положить в файл с именем roundtest.rb и выполнить распечатки

bash> ruby roundtest.rb
1.14   1.1  
1.15   1.2  
1.16   1.2  
1.4   1.0  
1.5   2.0  
1.6   2.0  

Обратите внимание на легкость округления до ближайших 2, 15, 0,005 или чего-либо еще.

0 голосов
/ 23 декабря 2009

Умножьте на 100, затем округлите, затем разделите на 100:

(1.15 * 100).round / 100.0 # => 1.15

Это не совсем элегантно, но избегает использования строк.

...