Можно также ввести совершенно новый оператор для приближенного сравнения, назвав его, например,
=~
.
Имейте в виду, что это нельзя назвать настоящим решением. При
последовательных вычислениях погрешность накапливается. Если вам совершенно необходимы числа с плавающей точкой, смиритесь с неточностями (см. также разделы 5.8 и 5.9).
5.5. Форматирование чисел для вывода
Для вывода числа в заданном формате применяется метод
printf
из модуля Kernel. Он практически не отличается от одноименной функции в стандартной библиотеке С. Дополнительную информацию см. в документации по методу
printf
.
x = 345.6789
i = 123
printf("x = %6.2f\n", x) # x = 345.68
printf("x = %9.2e\n", x) # x = 3.457e+02
printf("i = %5d\n\ i) # i = 123
printf("i = %05d\n", i) # i = 00123
printf("i = %-5d\n\, 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
:
9
Трактат «Искусство войны».
num1 = 1000000 # Один миллион (10**6)
num2 = num1*num1 #
Один триллион (10**12)
puts num1 # 1000000
puts num1.class # Fixnum
puts num2 # 1000000000000
puts num2.class # Bignum
Размер
Fixnum
зависит от машинной архитектуры. Вычисления с объектами
Bignum
ограничены только объемом памяти и быстродействием процессора. Конечно, они потребляют больше памяти и выполняются несколько медленнее, тем не менее операции над очень большими целыми (сотни знаков) реальны.
5.8. Использование класса BigDecimal
Стандартная библиотека
bigdecimal
позволяет работать с дробями, имеющими много значащих цифр. Число хранится как массив цифр, а не преобразуется в двоичное представление. Тем самым достижима произвольная точность, естественно, ценой замедления работы.
Чтобы оценить преимущества, рассмотрим следующий простой фрагмент кода, в котором используются числа с плавающей точкой:
if (3.2 - 2.0) == 1.2
puts "равны"
else
puts "не равны" # Печатается "не равны"!
end
В подобной ситуации на помощь приходит класс
BigDecimal
. Однако в случае бесконечных периодических дробей проблема остается. Другой подход обсуждается в разделе 5.9 «Работа с рациональными числами».
Объект
BigDecimal
инициализируется строкой. (Объекта типа
Float
было бы недостаточно, поскольку погрешность вкралась бы еще до начала конструирования
BigDecimal
.) Метод
BigDecimal
эквивалентен
BigDecimal.new
; это еще один особый случай, когда имя метода начинается с прописной буквы. Поддерживаются обычные математические операции, например
+
и
*
. Отметим, что метод
to_s
может принимать в качестве параметра форматную строку. Дополнительную информацию вы найдете на сайте ruby-doc.org.
require 'bigdecimal'
x = BigDecimal("3.2")
y = BigDecimal("2.0")
z = BigDecimal("1.2")
if (x - y) == z
puts "равны" # Печатается "равны"!
else
puts "не равны"
end
а = x*y*z
a.to_s # "0.768Е1" (по умолчанию: научная нотация)
a.to_s("F") # "7.68" (обычная запись)
Если необходимо, можно задать число значащих цифр. Метод
precs
возвращает эту информацию в виде массива, содержащего два числа: количество использованных байтов и максимальное число значащих цифр.
x = BigDecimal ("1.234",10)
y = BigDecimal("1.234",15)
x.precs # [8, 16]
y.precs # [8, 20]
В каждый момент число использованных байтов может оказаться меньше максимального. Максимум может также оказаться больше запрошенного вами (поскольку
BigDecimal
пытается оптимизировать использование внутренней памяти). У обычных операций (сложение, вычитание, умножение и деление) есть варианты принимающие в качестве дополнительного параметра число значащих цифр. Если результат содержит больше значащих цифр, чем указано, производится округление до заданного числа знаков.