аппаратура упрямо считает их различными.
Ниже показан простой способ выполнения сравнения с «поправкой», когда числа считаются равными, если отличаются не более чем на величину, задаваемую программистом:
class Float
EPSILON = 1e-6 # 0.000001
def == (x)
(self-x).abs < EPSILON
end
end
x = 1000001.0/0.003
y = 0.003*x
if y == 1.0 # Пользуемся новым оператором ==.
puts 'да' # Теперь печатается 'да'.
else
puts 'нет'
end
В зависимости от ситуации может понадобиться задавать разные погрешности. Для этого определим в классе Float
новый метод equals?
. (При таком выборе имени мы избежим конфликта со стандартными методами equal?
и eql?
; последний, кстати, вообще не следует переопределять).
class Float
EPSILON = 1e-6
def equals?(x, tolerance=EPSILON)
(self-x).abs < tolerance
end
end
flag1 = (3.1416).equals? Math::PI # false
flag2 = (3.1416).equals?(Math::PI, 0.001) # true
Можно также ввести совершенно новый оператор для приближенного сравнения, назвав его, например, =~
.
Имейте в виду, что это нельзя назвать настоящим решением. При последовательных вычислениях погрешность накапливается. Если вам совершенно необходимы числа с плавающей точкой, смиритесь с неточностями (см. также разделы 5.8 и 5.9).
5.5. Форматирование чисел для вывода
Для вывода числа в заданном формате применяется метод printf
из модуля Kernel. Он практически не отличается от одноименной функции в стандартной библиотеке С. Дополнительную информацию см. в документации по методу printf
.
x = 345.6789
i = 123
printf('x = %6.2f
', x) # x = 345.68
printf('x = %9.2e
', x) # x = 3.457e+02
printf('i = %5d
i) # i = 123
printf('i = %05d
', i) # i = 00123
printf('i = %-5d
, i) # i = 123
Чтобы сохранить результат в строке, а не печатать его немедленно, воспользуйтесь методом sprintf
. При следующем обращении возвращается строка:
str = sprintf ('%5.1f',x) # '345.7'
Наконец, в классе String
есть метод %
, решающий ту же задачу. Слева от знака %
должна стоять форматная строка, а справа — единственный аргумент (или массив значений), результатом является строка.
# Порядок вызова: 'формат % значение'
str = '%5.1f' % x # '345.7'
str = '%6.2f, %05d' % [x,i] # '345.68, 00123'
5.6. Вставка разделителей при форматировании чисел
Возможно, есть и более удачные способы достичь цели, но приведенный ниже код работает. Мы инвертируем строку, чтобы было удобнее выполнять глобальную замену, а в конце инвертируем ее еще раз:
def commas(x)
str = x.to_s.reverse
str.gsub!(/([0-9]{3})/,'\1,')
str.gsub(/,$/,'').reverse
end
puts commas(123) # '123'
puts commas(1234) # '1,234'
puts commas(12345) # '12,435'
puts commas(123456) # '123,456'
puts commas(1234567) # '1,234,567'
5.7. Работа с очень большими числами
Управлять массами все равно что управлять немногими: дело в частях и в числе.
При необходимости Ruby позволяет работать с произвольно большими целыми числами. Переход от Fixnum
к Bignum
производится автоматически, прозрачно для программиста. В следующем разделе результат оказывается настолько большим, что преобразуется из объекта Fixnum
в Bignum
:
num1 = 1000000 # Один миллион (10**6)
num2 = num1*num1 # Один триллион (10**12)
puts num1 # 1000000
puts num1.class # Fixnum