2010-07-28 3 views
2

Я инициализирую экземпляр класса, который проверяет равенство двух формул.Порядок операций в Ruby

вычисленных значений этой формулы фактически равен:

RubyChem::Chemical.new("SOOS").fw 
=> 96.0 

RubyChem::Chemical.new("OSSO").fw 
= 96.0 

Когда я создал новый класс, чтобы проверить равенство этих двух случаев я немного удивлены результатами:

x = RubyChem::BalanceChem.new("SOOS","OSSO") 
x.balanced 
=>false 

y = RubyChem::BalanceChem.new("SOOS","SOOS") 
y.balanced 
=> true 

RubyChem :: BalanceChem инициализировать метод здесь:

def initialize(formula1, formula2) 
    @balanced = RubyChem::Chemical.new(formula1).fw == RubyChem::Chemical.new(formula2).fw 
end 

Почему не рубин принести ФВ значения для формулы 1 и формулы 2 и проверить равенство этих значений? Каков порядок операций в Ruby и что делает Ruby? Я вижу, что мне не хватает понимания этой проблемы. Как я могу сделать эту работу? Заранее спасибо.

ответ

3

Вы, вероятно, не хотят, чтобы проверить чисел с плавающей точкой на равенство. Вместо этого вы должны сравнить дельт.

Попробуйте это в IRB:

x = 1.000001 
y = 1.0 
x == y 
(x-y).abs < 0.00001 

Итак, вы нашли дельту как 0,00001, что вы чувствуете, будет обрабатывать любые изменения в арифметики с плавающей точкой, и использовать его таким образом. Вы никогда не должны == плавает.

+0

Что бы вы использовали, а не плавающие точки для сравнения? В химии наиболее специфической мне может быть .00001; Есть ли какое-либо преимущество в использовании плавающих точек в математических операциях? –

+1

Нет никаких особых преимуществ использования плавающих точек вместо других типов, и чтобы быть совершенно точными, вам также необходимо будет учитывать значимые цифры и обрабатывать вопросы округления. Тем не менее, умножение всего на 10k и использование целочисленной математики также проблематично, поэтому на данный момент я буду придерживаться float. Если вам нужна самая высокая точность .00001, лучший способ справиться с этим сравнением - это метод, описанный выше, используя (x-y) .abs <0.000001 или около того как максимальная дельта для равенства. Ошибка обычно превышает диапазон 1е-9, так что это будет нормально. – drharris

4

Ruby 1.8 имеет bug when converting floats to string. Иногда данная строка не является хорошим представлением поплавка. Вот пример с 0.56:

0.5600000000000005.to_s == 0.56.to_s #=> true 
# should have returned false, since: 
0.5600000000000005  == 0.56  #=> false 

Это объясняет, почему два, по-видимому, идентичные результаты не являются фактически идентичными.

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

Смежные вопросы