Чтение онлайн

ЖАНРЫ

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

a = BigDecimal("1.23456")

b = BigDecimal("2.45678")

# В комментариях "BigDecimal:objectid" опущено.

c = a+b # <'0.369134Е1\12(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.30330423168E1\16(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 или любому подробному справочному руководству.

5.9. Работа с рациональными числами

Класс

Rational
позволяет (во многих случаях) производить операции с дробями с «бесконечной» точностью, но лишь если это настоящие рациональные числа (то есть частное от деления двух целых чисел). К иррациональным числам, например или e, он неприменим.

Для создания рационального числа мы вызываем специальный метод

Rational
(еще один из немногих методов, имя которого начинается с прописной буквы; обычно такие методы служат для преобразования данных или инициализации).

r = Rational(1,2) # 1/2 или 0.5

s = Rational(1,3) # 1/3 или 0.3333...

t = Rational(1,7) # 1/7 или 0.14...

u = Rational(6,2) # "то же самое, что" 3.0

z = Rational(1,0) # Ошибка!

Результатом операции над двумя рациональными числами, как правило, снова является рациональное число.

r+t # Rational(9, 14)

r-t # Rational(5, 14)

r*s # Rational(1, 6)

r/s # Rational(3, 2)

Вернемся к примеру, на котором мы демонстрировали неточность операций над числами с плавающей точкой (см. раздел 5.4). Ниже мы выполняем те же действия над рациональными, а не вещественными числами и получаем «математически ожидаемый» результат:

x = Rational(1000001,1)/Rational(3,1000)

y = Rational(3,1000)*x

if y == 1000001.0

 puts "да" #
Теперь получаем "да"!

else

 puts "нет"

end

Конечно, не любая операция дает рациональное же число в качестве результата:

x = Rational (9,16) # Rational(9, 16)

Math.sqrt(x) # 0.75

x**0.5 # 0.75

x**Rational(1,2) # 0.75

Однако библиотека

mathn
в какой-то мере изменяет это поведение (см. раздел 5.12).

5.10. Перемножение матриц

Стандартная библиотека

matrix
предназначена для выполнения операций над числовыми матрицами. В ней определено два класса:
Matrix
и
Vector
.

Следует также знать о прекрасной библиотеке

NArray
, которую написал Масахиро Танака (Masahiro Tanaka) — ее можно найти на сайте www.rubyforge.org. Хотя эта библиотека не относится к числу стандартных, она широко известна и очень полезна. Если вы предъявляете повышенные требования к быстродействию, нуждаетесь в особом представлении данных или желаете выполнять быстрое преобразование Фурье, обязательно ознакомьтесь с этим пакетом. Впрочем, для типичных применений стандартной библиотеки
matrix
должно хватить, поэтому именно ее мы и рассмотрим.

Чтобы создать матрицу, мы, конечно же, обращаемся к методу класса. Сделать это можно несколькими способами. Самый простой — вызвать метод

Matrix.[]
и перечислить строки в виде массивов. Ниже мы записали вызов на нескольких строчках, но, разумеется, это необязательно:

m = Matrix[[1,2,3],

[4,5,6],

[7,8,9]]

Вместо этого можно вызвать метод rows, передав ему массив массивов (в таком случае «дополнительные» скобки необходимы). Необязательный параметр сору, по умолчанию равный true, указывает, надо ли скопировать переданные массивы или просто сохранить на них ссылки. Оставляйте значение true, если нужно защитить исходные массивы от изменения, и задавайте false, если это несущественно.

Row1 = [2,3]

row2 = [4,5]

m1 = Matrix.rows([row1,row2]) # copy=true

m2 = Matrix.rows([row1,row2],false) # He копировать.

row1[1] = 99 # Теперь изменим row1.

p m1 # Matrix[[2, 3], [4, 5]]

p m2 # Matrix[[2, 99], [4, 5]]

Можно задать матрицу и путем перечисления столбцов, если воспользоваться методом

columns
. Ему параметр
сору
не передается, потому что столбцы в любом случае расщепляются, так как во внутреннем представлении матрица хранится построчно:

m1 = Matrix.rows([[1,2],[3,4]])

m2 = Matrix.columns([[1,3],[2,4]]) # m1 == m2

Предполагается, что все матрицы прямоугольные, но это не проверяется. Если вы создадите матрицу, в которой отдельные строки или столбцы длиннее либо короче остальных, то можете получить неверные или неожиданные результаты.

Некоторые специальные матрицы, особенно квадратные, конструируются проще. Так, тождественную матрицу конструирует метод

identity
(или его синонимы
I
и
unit
):

Поделиться с друзьями: