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

Теперь в деталях:

  1. мы производим последовательность с Sequence{a..b}
  2. эта последовательность идет от 1 на большее число между x а также y (if x < y then Sequence{1..y} else Sequence{1..x})
  3. эта последовательность хранится в неизменяемой переменной divs (let divs : Sequence(Integer) = ... in ...)
  4. от divsВыбираем только номер z который является делителем для x а также z (divs->select(z | x.mod(z) = 0 and y.mod(z) = 0)
  5. наконец, мы берем только последний элемент из новой последовательности (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()
Другие вопросы по тегам