Смекни!
smekni.com

Программирование и разработка приложений в Maple (стр. 31 из 135)

Следует отметить, что в таблицах главы и в последующих не приводится исчерпывающей характеристики функций либо других средств Maple-языка, а только основные их назначение и аргументы. Некоторые их особенности приводятся в прилож. 3 [12], полную же информацию по любой функции, поддерживаемой пакетом, можно оперативно получать по конструкции ?<функция> или в документации по Maple, например, [8183,89]. Следует еще раз напомнить, что кодирование идентификаторов в пакете Maple регистро-зависимо, поэтому необходимо правильно кодировать все используемые идентификаторы. Несоблюдение данного условия лежит в основе многих ошибок.

1.8. Функции математической логики и средства тестирования пакета

Для решения задач математической логики, пропозиционального исчисления, а также организации логических конструкций, управляющих вычислительным процессом в документе Maple либо программе (условные переходы, ветвления, циклические и итеративные вычисления и др.), Maple-язык располагает рядом встроенных, библиотечных и модульных процедур и функций, операторов и иных конструкций, значения аргументов или возвращаемых результатов которых получают логические значения true (истина), false (ложь) и FAIL (неопределенность). К группе данных средств относятся и так называемые тестирующие функции и процедуры. Такие средства в зависимости от результата тестирования своего аргумента возвращают значение true или false. Ряд свойств таких функций нами рассматривался выше в связи с другими вопросами Maple-языка, остальные будут рассматриваться здесь и в последующих разделах по мере необходимости и в контексте с различными вопросами практического программирования.

В основе математической логики, поддерживаемой Maple-языком, лежит понятие булевого (boolean; логического) выражения. Как уже отмечалось, Maple-язык поддерживает трехзначную логику {true, false, FAIL} для всех булевых операций. Булевы выражения формируются на основе базовых логических операторов {and, or, not}, образующих функционально полную систему (в смысле возможности представления на их основе произвольной логической функции) и операторов отношения {< (меньше)|<= (не больше)|> (больше)|>= (не меньше)|= (равно)|<> (не равно)}. Булевский (boolean) тип идентифицируется тестирующими функциями type и typematch, и процедурой whattype; и при этом, Maple-язык дифференцирует boolean-тип на два базовых подтипа: relation и logical. К relation-подтипу относятся выражения вида {<|<=|=|<>}, а к logical-подтипу - выражения вида {or, and, not}; тогда как boolean-тип определяют как собственно выражения двух указанных подтипов, так и их сочетания, а также логические константы {true, false}. Все логические типы тестируются {type|typematch}-функцией следующего формата кодирования:

{type|typematch}(<Выражение>, {boolean|relation|logical})

как это иллюстрирует следующий простой пример:

> [type(AV <> 64, 'relation'), type(AV and AG, 'logical'), type(true <> false, 'boolean')],

[whattype(AV and AG), typematch(AV <> 59, 'relation')]; ⇒ [true, true, true], [and, true] Для вычисления Maple-выражений в булевой трактовке используется evalb-функция, имеющая простой формат кодирования: evalb(<Выражение>) и возвращающая логическое значение {true|false|FAIL}; если это невозможно, то выражение возвращается невычисленным. Основной задачей evalb-функции является вычисление Maple-выражений, содержащих операторы отношения, в терминах логических значений. Это необходимо в целом ряде случаев, связанных с различного рода задачами анализа вычислительных конструкций, ибо Maple-язык трактует выражения, содержащие операторы отношения, как алгебраические уравнения или неравенства, если выражения дополнительно не содержат логических {and, or, not}-операторов. И только в качестве аргументов evalb-функции либо в {if|while}-предложениях Maple-языка они получают логическую трактовку. При этом, следует иметь в виду, что Maple-язык конвертирует выражение, содержащее операторы отношения {>, >=}, в эквивалентное ему выражение в терминах {<, <=}-операторов. Более того, т.к. evalb-функция не производит упрощения выражения-аргумента, то в ряде случаев ее применение может приводить к некорректным результатам. Поэтому, перед вызовом evalb-функции рекомендуется предварительно упрощать выражение, передаваемое ей в качестве фактического аргумента; это можно, в частности, делать и по simplify-функции. Простой фрагмент иллюстрирует вышесказанное:

> whattype(AVZ = AGN), evalb(AVZ = AGN), evalb(AVZ = AVZ); ⇒ =, false, true

> AV:= 64: whattype(AV <= 64), evalb(AV = 64), evalb(AV <= 64); ⇒ <=, true, true > whattype(sqrt(64) <> ln(17)), evalb(sqrt(64) <> ln(17)); ⇒ <>, true

Следует иметь в виду, что вычисление логических выражений подчиняется следующему правилу: первым вычисляется левый операнд {and|or}-оператора и вычисление правого его операнда производится только тогда, когда логическое значение левого операнда может способствовать получению true-значения выражения в целом. Так, правый операнд логического and-выражения следующего вида:

> G:= 0: V:= 17: if (G = 64) and (V/G >= 0.25) then printf(`%3s&bsol;%4f`, `G=`, V/G) end if;

> G:= 0: V:= 20: if (G = 52) or (V/G >= 9.47) then printf(`%3s&bsol;%4f`, `G=`, V/G) end if; Error, numeric exception: division by zero не вычисляется и не вызывает ошибочной ситуации “деления на нуль”, т.к. левый его операнд (G = 64) для G = 0 при вычислении возвращает false-значение, не способствующее получению true-значения and-оператора в целом, независимо от результата вычисления его правого операнда, вызывающего на данном G-значении указанную ошибочную ситуацию. Иная ситуация, как показано, имеет место для случая or-оператора.

Правила выполнения логических {and,or,not}-операторов на {true, false, FAIL}-значениях в качестве операндов определяются следующими таблицами истинности:

and

true

false

FAIL

or

true

false

FAIL

not

true

true

false

FAIL

true

true

true

true

true

false

false

false

false

false

false

true

false

FAIL

false

true

FAIL

FAIL

false

FAIL

FAIL

true

FAIL

FAIL

FAIL

FAIL

Смысл приведенных правил достаточно прозрачен и пояснений не требует, например: > [FAIL and true, false or FAIL, true or FAIL, not FAIL]; ⇒ [FAIL, FAIL, true, FAIL]

Следует отметить, что до 6-го релиза Maple для расширения круга решаемых задач математической логики и ее приложений дополнительно предоставлял 10 модульных функций, поддерживаемых средствами logic-модуля. Однако, после нашей принципиальной критики ряда его функций, точнее результатов вызовов bequal-функции на FAIL-значениях [10-12], данный модуль был исключен из Maple. И аналога этого (в целом весьма полезного) модуля не было до Maple 10. И только в последнем релизе появился модуль Logic, чьи средства предна-начены для работы с выражениями, используя двузначную булеву логику, т.е. без FAIL-значения. По конструкции ?Logic читатель может детально ознакомиться со средствами данного модуля.

Bit := proc( B::{string symbol, , list(integer)}, bits::{procedure, list {( equation integer, })}) local a b c k, , , ; c := x → [seq(parse(x k[ ]), k = 1 .. length( )x )]; if type(B, {'symbol', 'string'}) and length(B) = 1 then a := c(cat("", convert(op(convert(B, 'bytes')), 'binary'))); b := [0 $ (' 'k = 1 .. 8 − nops(a)), op(a)] elif type(B, 'list'('integer')) and nops(B) = 1 and belong(B[1], 0 .. 255) then a := c(cat "",( convert(op(B), 'binary'))); b := [0 $ (' 'k = 1 .. 8 − nops(a)), op(a)]

else error "1st argument must be symbol/string of length 1 or integer list, but &bsol; as received <%1>", B end if; if type(bits, 'list'('integer')) and belong {( op(bits)}, 1 .. 8) then [seq(b k[ ], k = {op(bits)})] elif type(bits, 'list'('equation')) and belong({seq(lhs(k), k = bits)}, 1 .. 8) and belong {( seq(rhs( )k , k = bits)}, 0 .. 1) then seq(assign(' 'b[lhs(bits k[ ])] = rhs(bits k[ ])), k = 1 .. nops(bits)); convert(parse cat(( op map(( convert b, , 'string')))), 'decimal', 'binary') elif type(bits, 'procedure') then convert(parse(cat(op(map(convert, bits(b), 'string')))), 'decimal', 'binary')

else error "2nd argument <%1> is invalid", bits end if

end proc > Bit(`S`,[k$k=1..8]),Bit([59],[1,3,8]), Bit([59],[2=1,4=0,8=0]),Bit("G",[6]),Bit("0",[6=1,7=1,8=1]);

[0, 1, 0, 1, 0, 0, 1, 1], [0, 1, 1], 106, [1], 7

> R:=(L::list) -> [L[nops(L)-k]$k=0..nops(L)-1]: Bit("G", [k$k=1..8]), Bit("G", R), Bit("S", R), Bit([59], R); ⇒ [0, 1, 0, 0, 0, 1, 1, 1], 226, 202, 220

Для обеспечения логических операций и по-битной (поразрядной) обработки информации нами также был определен ряд процедур и модулей [42,103,109]. Так вышеприведенная процедура Bit(B, bits) обеспечивает выполнение следующих базовых по-битных операций с символом, указанным первым аргументом В (в качестве В могут выступать 1-элементные строка либо символ, а также 1-элементный список, чей элемент определяет десятичный код символа из диапазона 0..255):

(1) если второй аргумент bits имеет вид [n1, n2, …], вызов процедуры Bit(B, bits) возвращает значения битов символа B, расположенных в его позициях nj (nj лежит в 1 .. 8); (2) если второй аргумент bits имеет вид [n1 = b1, n2 = b2, …], возвращается десятичный код символа, полученного заменой значений битов символа В (в его позициях nk) на бинарные значения bk (nk = 1..8; bk = {0|1}).

(3) если второй аргумент bits – имя процедуры, определенной над списками, возвращается результат применения процедуры к списку значений всех битов символа В.

Наконец, в двух последних случаях возвращается десятичный код символа – результата обработки исходного символа В.

Базовые средства поддержки булевой алгебры обеспечиваются модулем boolop, а также нижеследующей процедурой BitWise [103,108,109]: