суббота, 5 декабря 2015 г.

Freemat. ООП

С увеличением уровня сложности компьютерного расчёта разница между ним и программой стирается (если вообще имела место быть). По-этому пользователю вполне может пригодиться такая проверенная временем технология, как возможность создания объектов и манипулирования ими ( == объектно-ориентированное программирование). В качестве примера попробуем создать класс для работы с рациональными числами rat.


Для простоты будем считать, что в расчёте используются либо целые числа, либо рациональные, либо их комбинация. Но прежде чем перейти непосредственно к реализации класса, напишем функцию для поиска наибольшего общего делителя (среди стандартных функций FreeMat 4.0 я её не нашёл, возможно, в следующих версиях что-то есть).
Строки 5 и 6 преобразуют агрументы в неотрицательные величины, можно также использовать функцию abs(). Затем меньшее из чисел помещается в переменную y, большее - в a. В FreeMat переменные передаются в функцию по значению, по-этому их изменение в теле функции не повлияет на исходные переменные. Сам поиск наибольшего общего делителя реализован в строках 14 - 18 по алгоритму Евклида. Нахождение остатка заменено функцией взятия по модулю mod().

Теперь перейдём к классу rat. Первое, что нужно сделать для его реализации - создать папку с именем '@rat' в каталоге программы FreeMat, к которому она имеет доступ по-умолчанию. Теперь можно реализовать конструктор, т.е. функцию, котрая на основе заданных аргументов вернёт нам объект класса rat. Вот возможный вариант реализации.
Если функци rat() передаётся 2 аргумента, считается, что это числитель и знаменатель. При одном аргументе делается проверка на его тип, если это объект класса rat, он копируется, если просто целое число - становится числителем. Если аргументов нет совсем, либо их больше 2-х, устанавливаем значение по-умолчанию - 0. Во всех случаях данные хранятся в виде структуры с полями 'num' (числитель) и 'denom' (знаменатель). Последняя строка преобразует структуру в класс rat.

В определении класса задействована вспомогательная функция rat_simp(), описанная ниже в этом же файле. 
Данная функция сокращает два передаваемых ей числа на величину наибольшего общего делителя, а также корректирует знаки, чтобы знаменатель всегда был положительным. 

Файл с конструктором 'rat.m', как и все последующие перегруженные методы класса, нужно сохранить в папке '@rat'. Имейте ввиду, что FreeMat определяет список классов и их методов при загрузке программы, по-этому нужно перезапустить программу для работы с новым классом.

Итак, у нас есть класс rat, но он бесполезен, т.к. ничего не умеет делать, FreeMat даже не может обеспечить адекватный доступ к его полям. Пока. Попробуем перезагрузить некоторые стандартные методы.

Отображение рационального числа в виде 'числитель / знаменатель'.
%     display.m
function display(obj)
    disp(sprintf('%d / %d', obj.num, obj.denom)) 
Функция sprintf() здесь формирует строку с заданным форматом отображения и передаёт её функции disp().

Что касается доступа к полям, мы говорим программе, что нас вполне устраивают встроенные (builtin) функции и ничего менять не нужно.
%     subsasgn.m
function B = subsasgn(A, S, B)
    B = builtin('subsasgn', A, S, B);

%     subsref.m
function B = subsref(A, S)
    B = builtin('subsref', A, S);

Теперь после перезапуска программы создаваемые объекты должны отображаться так, как определено в display(), и мы получили возможность изменять значения рациональных чисел. Осталось определить основные арифметические операции, и можно приступать к расчётам... Но сперва переопределим ещё 2 встроенные функции, которые нам пригодятся. 

Унарный минус, т.е. изменения значения числа на противоположное.
%     uminus.m
function c = uminus(a)
    c = rat(-a.num, a.denom);

Поскольку в FreeMat нет обозначения для обратного числа, я переопределил операцию транспонирования.
%     ctranspose.m
function c = ctranspose(a)
    c = rat(a.denom, a.num);

Итак, умножение. Здесь учитывается возможность как перемножения рациональных чисел, так и домножение на целое число слева или справа.
Деление выражено через умножение с использованием взятия обратного числа, тип делителя предварительно корректируется (при необходимости).
Сумма рациональных чисел рассчитывается более сложно, чем произведение. Здесь оба слагаемых сразу приводятся к типу rat, затем определяется наименьшее общее кратное их знаменателей (как отношение произведения к наибольшему общему делителю), после чего уже рассчитывается сумма.
Разность выражается через сумму с предварительной корректировкой вычетаемого.

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






Комментариев нет:

Отправить комментарий