Наибольший общий делитель в Ocl
Как я могу написать операцию gcd(x : Integer, y : Integer) : Integer
который возвращает наибольший общий делитель двух натуральных чисел (наибольшее целое число, которое делит их обоих точно) в ocl
?
1 ответ
Вот простое решение для этого (конечно, не эффективно, но оно работает):
let divs : Sequence(Integer) = if x < y then Sequence{1..y} else Sequence{1..x} endif
in divs->select(z | x.mod(z) = 0 and y.mod(z) = 0)->last()
Что просто делается, так это то, что генерируется последовательность каждого потенциального кандидата, тогда из этой последовательности только те, которые делят x
а также y
выбираются и сохраняются в новой последовательности (которая упорядочена). Наконец, последнее число из этой отфильтрованной последовательности - ваш самый большой общий делитель.
Теперь в деталях:
- мы производим последовательность с
Sequence{a..b}
- эта последовательность идет от
1
на большее число междуx
а такжеy
(if x < y then Sequence{1..y} else Sequence{1..x}
) - эта последовательность хранится в неизменяемой переменной
divs
(let divs : Sequence(Integer) = ... in ...
) - от
divs
Выбираем только номерz
который является делителем дляx
а такжеz
(divs->select(z | x.mod(z) = 0 and y.mod(z) = 0)
- наконец, мы берем только последний элемент из новой последовательности (
select(...)->last()
)
Если last()
функция не существует в вашем env (не знаю почему, но некоторые реализации OCL предоставляют свои собственные функции), вы можете использовать:
->sortedBy(i | -i)->at(1)
вместо last()
, которые переворачивают последовательность и берут первый элемент.
EDIT>
Вы также можете уменьшить выражение следующим образом:
let divs : Sequence(Integer) = Sequence{1..x.max(y)}
in divs->select(z | x.mod(z) = 0 and y.mod(z) = 0)->last()
или, удалив использование divs
Sequence{1..x.max(y)}->select(z | x.mod(z) = 0 and y.mod(z) = 0)->last()