Книга: Программирование на языке Ruby

5.8. Использование класса BigDecimal

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 пытается оптимизировать использование внутренней памяти). У обычных операций (сложение, вычитание, умножение и деление) есть варианты принимающие в качестве дополнительного параметра число значащих цифр. Если результат содержит больше значащих цифр, чем указано, производится округление до заданного числа знаков.

a = BigDecimal("1.23456")
b = BigDecimal("2.45678")
# В комментариях "BigDecimal:objectid" опущено.
c = a+b          # <'0.369134Е112(20)>
c2 = a.add(b,4)  # <'0.3691Е1',8(20)>
d = a-b          # <'-0.122222E1',12(20)>
d2 = a.sub(b,4)  # <'-0.1222E1',8(20)>
e = a*b          # <'0.30330423168E116(36)>
e2 = a.mult(b,4) # <'0.3033E1',8(36)>
f = a/b          # <'0.502511417383729922907221E0',24(32)>
f2 = a.div(b,4)  # <'0.5025E0',4(16)>

В классе BigDecimal определено и много других функций, например floor, abs и т.д. Как и следовало ожидать, имеются операторы % и **, а также операторы сравнения, к примеру <. Оператор == не умеет округлять свои операнды — эта обязанность возлагается на программиста.

В модуле BigMath определены константы E и PI с произвольной точностью. (На самом деле это методы, а не константы.) Там же определены функции sin, cos, exp и пр.; все они принимают число значащих цифр в качестве параметра. Следующие подбиблиотеки являются дополнениями к BigDecimal.

bigdecimal/math     Модуль BigMath
bigdecimal/jacobian
Методы для вычисления матрицы Якоби

bigdecimal/ludcmp   Модуль LUSolve, разложение матрицы в произведение верхнетреугольной и нижнетреугольной

bigdecimal/newton   Методы nlsolve и norm

В настоящей главе эти подбиблиотеки не описываются. Для получения дополнительной информации обратитесь к сайту ruby-doc.org или любому подробному справочному руководству.

Оглавление книги

Оглавление статьи/книги

Генерация: 1.431. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз