Вход в систему
РФЭИ/ИТ
Сократимость Практика: обыкновенные дроби Язык программирования Scala
Базовые определения Неправильные дроби

Сократимость

Обыкновенную дробь называют несократимой, если ее числитель и знаменатель являются взаимнопростыми.

Наибольший общий делитель

Для определения взаимной простоты двух целых чисел, необходимо знать их наибольший общий делитель.

def gcd(x: Int, y: Int): Int =
  if (b == 0) a
  else if (a < 0) gcd(-a, b)
  else if (b < 0) gcd(a, -b)
  else if (b > a) gcd(b, a)
  else gcd(b, a % b)

Метод gcd (сокр. greatest common divisor — наибольший общий делитель) — это рекурсивная реализация алгоритма Евклида. Внимательно изучите его. Убедитесь, что полностью понимаете, как он работает, прежде чем следовать дальше.

Проверка на сократимость

Теперь добавим метод isReduced, показывающий несократимость дроби.

def isReduced = gcd(numerator, denominator) == 1

Как Вы уже догадались, метод isReduced возвращает логическое значение типа Boolean.

Сокращение дроби

Класс должен поддерживать вычисление несократимой дроби, равной заданной.

Добавим метод reduced, возвращающий несократимую дробь, равную заданной.

def reduced: Fraction =
  if (isReduced) this
  else new Fraction(
    numerator / gcd(numerator, denominator),
    denominator / gcd(numerator, denominator)
  )

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

Рефакторинг

Рефакторинг — это эквивалентные преобразования кода, сохраняющее общее поведение, но существенно увеличивающие его качества.

Обратите внимание на методы isReduced и reduced. Легко заметить, что вызов gcd(numerator, denominator) повторяется трижды. Выделим этот вызов в отдельный метод (такая операция рефакторинга называется extract method):

def gcd: Int = gcd(numerator, denominator)

Методы isReduced и reduced теперь можно упросить:

def isReduced = gcd == 1

def reduced: Fraction =
  if (isReduced) this
  else new Fraction(numerator / gcd, denominator / gcd)

При вызове reduced одно и то же значение наибольшего общего делителя может быть вычислено целых три раза. Поскольку поля numerator и denominator неизменяемы, мы легко можем заменить метод gcd на поле.

val gcd: Int = gcd(numerator, denominator)

Теперь наибольший общий делитель будет вычислен только один раз — в момент инициализации экземпляра. Отсутствие необходимости вычислений при каждом вызове методов reduced и isReduced существенно повышает их производительность.

Подробнее о взаимозаменяемости полей и методов Вы узнаете при обсуждении принципов единообразного доступа.

Проверка

val f1 = new Fraction(8,-6)
f1: Fraction = -8/6
val f2 = f1.reduced
f2: Fraction = -4/3
f1.isReduced
res0: Boolean = false
f2.isReduced
res0: Boolean = true
Базовые определения Неправильные дроби
2012 © ООО «Территория Образования»
Сделано с помощью Circumflex