Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Рациональные числа JS: Составные данные

Абстракция

Пары отлично подходят для представления рациональных чисел. Первый элемент пары может выступать числителем, а второй элемент — знаменателем.

a / b  (a, b)

Мы увидели, как пары могут использоваться для представления разных структур, а сочетания таких представлений — создавать новые структуры.


Конспект урока

Ещё одной очень простой и интересной абстракцией, помимо графических примитивов, являются так называемые рациональные числа. С рациональными числами знакомы все. Рациональным называют число, которое можно представить в виде обыкновенной дроби. Обыкновенная дробь состоит из двух чисел — числителя и знаменателя, поэтому эта абстракция идеально ложится на пары. Интерфейс нам уже знаком и состоит из конструктора и двух селекторов:

const rat = rational.make(5, 4);
rational.numer(rat); // 5
rational.denom(rat); // 4

Конструктор make принимает два числа. Селектор numer ответственен за получение числителя, denom — знаменателя.

На рациональных числах определены различные операции, например, сложение рациональных чисел, умножение — всё это происходит по определённым правилам:

n1/d1 + n2/d2 = (n1 * d2 + n2 * d1) / (d1* d2)

n1/d1 * n2/d2 = (n1 * n2) / (d1 * d2)

А по такой формуле работает функция isEqual, которая проверяет равенство дробей:

n1/d1 = n2/d2, *if* n1 * d2 = n2 * d1

Абстракция позволяет нам делать некоторые интересные вещи так, чтобы остальная часть программы об этом не знала. Например, нормализация дроби:

add(make(1, 10), make(4, 10)); // 5/10

Сложив два числа из примера, мы получим 5/10, что является одним из представлений числа 1/2 или 10/20 (обычно нормализуют в меньшую сторону). Когда мы говорим про работу с абстракцией, у нас есть несколько способов провести нормализацию числа. Например, это можно делать при вызове конструктора:

make(5, 10); // 1/2

Тогда нормализация будет производиться один раз при создании рационального числа. Другой способ — делать нормализацию при вызове селекторов:

numer(make(5, 10)); // 1
denom(make(5, 10)); // 2

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

Есть ещё один интересный случай — нормализация знака. Например, при создании рационального числа, в котором числитель или знаменатель отрицателен, нам нужно как-то сохранить информацию об этом, чтобы само рациональное число было отрицательным:

make(-1, 2); // - 1/2

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

При этом есть различные пограничные случаи, например:

add(make(-1, -4), make(2, 4)); // 3/4

В примере выше и числитель и знаменатель в первом рациональном числе — отрицательные числа. В таком случае два знака - у дроби должны уходить. А значит, функция make должна знать об этом. Само по себе это не заработает, и вместо правильного результата могут появляться совершенно непредсказуемые эффекты.

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


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнения
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 120 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»