Целочисленная арифметика¶
Специальный символ, выполняющий арифметические вычисления. В выражении a * b символ * — оператор умножения, a и b — его операнды.
Оператор, принимающий два операнда, называется бинарным. Унарный оператор принимает один операнд. Пример унарного оператора: -1 .
Последовательность операторов и операндов, результат вычисления которой сводится к единственному значению. Простейшие выражения состоят из одного значения и не содержат операторов: 42 , "Hello, World!" . Пример более сложного выражения: 2 ** 32 — 1 .
Свойство оператора, влияющее на очередность его выполнения в выражении с несколькими различными операторами при отсутствии явного (с помощью скобок) указания на порядок их вычисления.
Например, результат выражения 2 + 2 * 2 — 6, поскольку приоритет операции умножения выше, чем приоритет операции сложения. Изменить порядок вычислений в выражении можно с помощью скобок:
последовательность выполнения операций (или направление вычисления), реализуемая когда операции имеют одинаковый приоритет и отсутствует явное (с помощью скобок) указание на очерёдность их выполнения.
Различают правую (справа налево) и левую (слева направо) ассоциативность. Пример оператора с левой ассоциативностью — оператор деления / . Так, выражение 8 // 4 // 2 эквивалентно (8 // 4) // 2 и его результат равен 1.
Пример оператора с правой ассоциативностью — оператор возведения в степень:
Арифметические операторы¶
В таблице приведены некоторые арифметические операторы языка Python в порядке уменьшения приоритета (операторы с наибольшим приоритетом расположены выше).
Возведение в степень
Унарные плюс и минус
Сложение и вычитание
Целочисленное деление и взятие остатка от деления¶
Рассмотрим выражение \(7 / 2\) . Частное можно записать в виде десятичной дроби: \(3.5\) . Однако в ряде задач нам нужны отдельно целая часть и остаток от деления. Очевино, целая часть результата равна \(3\) . Тогда для вычисления остатка от \(7\) нужно отнять произведение целой части на делимое, т.е. остаток равен \(7 — 3 \cdot 2\) .
Такие операции поддерживаются в Python напрямую. Так, для целочисленного деления используется оператор // , а для получения остатка от деления оператор % :
Эти операции полезны при вычислениях с отдельными разрядами чисел.
Пусть дано число \(8192\) , и нам необходимо получить его третий разряд, т.е. единицу. \(8192 // 10^2 \% 10 = 8192 // 100 \% 10 = 81 \% 10 = 1\) .
Функции перевода чисел в различные системы счисления¶
Функции принимают целое число и возвращают его строковое представление в двоичной, восьмеричной и шестнадцатеричной системах счисления соответственно.
С этой функцией мы познакомились на прошлом занятии. Сейчас дополним, что вторым аргументом она может принимать основание системы счисления, в которой записано число x :
Задачи¶
Дано целое десятичное число. Выведите его последнюю цифру.
Дано целое десятичное число. Найдите число десятков в его десятичной записи.
Дано трехзначное число. Найдите сумму его цифр.
Пирожок в столовой стоит \(a\) рублей и \(b\) копеек. Определите, сколько рублей и копеек нужно заплатить за \(n\) пирожков.
Приложение запрашивает у пользователя стоимость одного пирожка и количество пирожков. Пример:
Приложение должно вычислить стоимость запрошенного количества пирожков. Пример вывода:
Дано число \(n\) . С начала суток прошло n минут. Определите, сколько часов и минут будут показывать электронные часы в этот момент. Программа должна вывести два числа: количество часов (от 0 до 23) и количество минут (от 0 до 59). Учтите, что число \(n\) может быть больше, чем количество минут в сутках.
Дополнительные задачи¶
В школе решили набрать три новых математических класса. Так как занятия по математике у них проходят в одно и то же время, было решено выделить кабинет для каждого класса и купить в них новые парты. За каждой партой может сидеть не больше двух учеников. Известно количество учащихся в каждом из трёх классов. Сколько всего нужно закупить парт чтобы их хватило на всех учеников? Программа получает на вход три целых десятичных числа: количество учащихся в каждом из трех классов.
Обувная фабрика собирается начать выпуск элитной модели ботинок. Дырочки для шнуровки будут расположены в два ряда, расстояние между рядами равно \(a\) , а расстояние между дырочками в ряду \(b\) . Количество дырочек в каждом ряду равно \(N\) . Шнуровка должна происходить элитным способом «наверх, по горизонтали в другой ряд, наверх, по горизонтали и т.д.» (см. рисунок). Кроме того, чтобы шнурки можно было завязать элитным бантиком, длина свободного конца шнурка должна быть \(l\) . Какова должна быть длина шнурка для этих ботинок?
Программа получает на вход четыре натуральных числа \(a\) , \(b\) , \(l\) и \(N\) и должна вывести одно число — искомую длину шнурка.
3. Занятия в школе начинаются в 9:00. Продолжительность урока — 45 минут, перемены — 10 минут. На вход принимается номер урока, а выводится время, в которое он заканчивается (часы и минуты отдельно). Пример вывода:
4. Доработайте код задачи № 3 таким образом, чтобы он запрашивал время начала занятий (минуты и часы отдельно) и номер урока, а далее также рассчитывал время окончания уроков.
5. Пользователь вводит число и систему счисления этого числа. Программа переводит число в десятичную, двоичную, восьмеричную и шестнадцетеричную системы счисления с использованием стандартных функций. Пример вывода:
Домашнее задание¶
Дано трехзначное число. Найти произведение его цифр.
Даны значения двух моментов времени, принадлежащих одним и тем же суткам: часы, минуты и секунды для каждого из моментов времени. Известно, что второй момент времени наступил не раньше первого. Определите, сколько секунд прошло между двумя моментами времени.
5.2 – Арифметические операторы
В C++ есть два унарных арифметических оператора, плюс (+) и минус (-). Напоминаем, что унарные операторы – это операторы, которые принимают только один операнд.
Оператор | Обозначение | Пример использования | Операция |
---|---|---|---|
Унарный плюс | + | +x | Значение x |
Унарный минус | — | -x | Отрицательное значение x |
Оператор унарного минуса возвращает операнд, умноженный на -1 . Другими словами, если x = 5 , -x равно -5 .
Оператор унарного плюса возвращает значение операнда. Другими словами, +5 равно 5 , а +x равно x . Как правило, вам не нужно использовать этот оператор, поскольку он избыточен. Он был добавлен в основном для обеспечения симметрии с унарным оператором минус.
Для наилучшего эффекта оба этих оператора следует размещать непосредственно перед операндом (например, -x , а не — x ).
Не путайте оператор унарного минуса с оператором бинарного вычитания, в котором используется тот же символ. Например, в выражении x = 5 — -3; первый минус – это оператор бинарного вычитания, а второй – оператор унарного минуса.
Бинарные арифметические операторы
В C++ есть 5 бинарных арифметических операторов. Бинарные операторы – это операторы, которые принимают левый и правый операнды.
Оператор | Обозначение | Пример использования | Операция |
---|---|---|---|
Сложение | + | x + y | x плюс y |
Вычитание | — | x — y | x минус y |
Умножение | * | x * y | x , умноженное на y |
Деление | / | x / y | x , деленное на y |
Остаток от деления | % | x % y | остаток от деления x на y |
Операторы сложения, вычитания и умножения работают так же, как и в реальной жизни, без каких-либо оговорок.
Деление и остаток от деления требуют дополнительных пояснений. О делении мы поговорим ниже, а об остатке от деления – в следующем уроке.
Целочисленное деление и деление с плавающей запятой
Проще всего представить себе, что оператор деления имеет два разных «режима».
Если один (или оба) операнда являются значениями с плавающей точкой, оператор деления выполняет деление с плавающей точкой. Деление с плавающей точкой возвращает значение с плавающей точкой, и дробная часть сохраняется. Например, 7.0 / 4 = 1.75 , 7 / 4.0 = 1.75 и 7.0 / 4.0 = 1.75 . Как и во всех арифметических операциях с плавающей точкой, здесь могут возникать ошибки округления.
Если оба операнда являются целыми числами, оператор деления вместо этого выполняет целочисленное деление. Целочисленное деление отбрасывает любые дробные части и возвращает целочисленное значение. Например, 7 / 4 = 1 , потому что дробная часть результата отбрасывается. Точно так же -7 / 4 = -1 , потому что дробная часть опускается.
Предупреждение
До C++11 целочисленное деление с отрицательным операндом могло округляться в большую или меньшую сторону. Таким образом, -5 / 3 могло дать результат -1 или -2 . Это было исправлено в C++11, где дробная часть всегда отбрасывается (округляется до 0).
Использование static_cast<> для деления с плавающей точкой с целочисленными значениями
Сказанное выше поднимает вопрос: если у нас есть два целых числа и мы хотим разделить их без потери дробной части, как нам это сделать?
В уроке «4.11 – Символы» мы показали, как можно использовать оператор static_cast<> для преобразования значения char в целочисленный тип, чтобы оно печаталось как целое число, а не как символ.
Аналогичным образом мы можем использовать static_cast<> для преобразования значения целочисленного типа в число с плавающей точкой, чтобы мы, вместо целочисленного деления, смогли выполнить деление с плавающей точкой. Рассмотрим следующий код:
Приведенный выше пример показывает, что если любой из операндов является числом с плавающей точкой, результатом будет деление с плавающей точкой, а не целочисленное деление.
Деление на ноль
Попытка разделить на 0 (или 0.0) обычно приводит к сбою программы, так как результаты математически не определены!
Это работает, но немного неудобно и требует для выполнения двух операторов ( operator+ и operator= ).
Поскольку написание таких инструкций, как x = x + 4 , очень распространено, C++ для удобства предоставляет пять арифметических операторов присваивания. Вместо того, чтобы писать x = x + 4 , вы можете написать x += 4 . Вместо x = x * y вы можете написать x *= y .
Деление (математика) — Division (mathematics)
Арифметическая операция 20/4 = 5, здесь показаны яблоки. В устной форме сказано: «Двадцать разделить на четыре равно пяти».
Деление — это одна из четырех основных операций арифметики, способов объединения чисел для образования новых чисел. Другими операциями являются сложение, вычитание и умножение (которые можно рассматривать как обратное деление). Знак деления ÷, символ, состоящий из короткой горизонтальной линии с точкой вверху и другой точкой внизу, часто используется для обозначения математического деления. Такое использование, хотя и широко распространено в англоязычных странах, не является универсальным и не рекомендуется: стандарт ISO 80000-2 для математической записи рекомендует только solidus / или дробная черта для деления или двоеточие для соотношений ; в нем говорится, что этот символ «не должен использоваться» для деления.
На элементарном уровне деление двух натуральных чисел — среди других возможных интерпретаций — процесс подсчета того, сколько раз одно число содержится в другом. Это количество раз не всегда является целым числом (числом, которое можно получить, используя другие арифметические операции с натуральными числами), что привело к двум различным концепциям.
деление с остатком или Евклидово деление двух натуральных чисел дает частное, которое представляет собой количество раз, когда второе число содержится в первом, и остаток, который — это часть первого числа, которая остается, когда в ходе вычисления частного больше не может быть выделено полной части размера второго числа.
Чтобы модификация этого деления давала только один единственный результат, натуральные числа должны быть расширены до рациональных чисел (чисел, которые могут быть получены с помощью арифметики с натуральными числами) или действительные числа. В этих расширенных системах счисления деление — это операция, обратная умножению, то есть a = c / b означает a × b = c, пока b не равно нулю. Если b = 0, то это деление на ноль, которое не определено.
Обе формы деления появляются в различных алгебраических структурах, различных способах определения математическая структура. Те, в которых определено евклидово деление (с остатком), называются евклидовыми областями и включают кольца многочленов в один неопределенный (которые определяют умножение и сложение над одиночными — переменные формулы). Те, в которых определено деление (с одним результатом) на все ненулевые элементы, называются полями и делительными кольцами. В кольце элементы, на которые всегда возможно деление, называются единицами (например, 1 и –1 в кольце целых чисел). Еще одно обобщение деления на алгебраические структуры — это фактор-группа , в которой результатом «деления» является группа, а не число.
Содержание
- 1 Введение
- 2 Нотация
- 3 Вычисления
- 3.1 Ручные методы
- 3.2 С помощью компьютера или с помощью компьютера
- 4.1 Евклидово разделение
- 4.2 Целых чисел
- 4.3 Рациональных чисел
- 4.4 Действительных чисел
- 4.5 Комплексных чисел
- 4.6 Полиномов
- 4.7 Матриц
- 4.7.1 Левое и правое деление
- 4.7.2 Псевдообратная
Введение
Простейший способ просмотра деления — это цитата и раздел : с точки зрения цитаты 20/5 означает количество пятерок, которые необходимо добавить, чтобы получить 20. С точки зрения разделения, 20/5 означает размер каждой из 5 частей, на которые разделен набор размером 20. Например, 20 яблок делятся на пять групп по четыре яблока, что означает, что двадцать, разделенные на пять, равны четырем. Это обозначается как 20/5 = 4 или 20/5 = 4. То, что делится, называется дивидендом, который делится на делитель, а результат называется частным. В этом примере 20 — это делимое, 5 — делитель, а 4 — частное.
В отличие от других основных операций, при делении натуральных чисел иногда возникает остаток, который не входит равномерно в делимое; например, 10/3 оставляет остаток 1, так как 10 не делится на 3. Иногда этот остаток добавляется к частному как дробная часть, поэтому 10/3 равно 3 + 1. / 3 или 3.33. но в контексте целочисленного деления, где числа не имеют дробной части, остаток сохраняется отдельно (в исключительных случаях отбрасывается или округляется ). Когда остаток сохраняется как дробь, получается рациональное число. Множество всех рациональных чисел создается путем расширения целых чисел всеми возможными результатами делений целых чисел.
В отличие от умножения и сложения, деление не является коммутативным, что означает, что a / b не всегда равно b / a. Деление также, как правило, не является ассоциативным, что означает, что при многократном делении порядок деления может изменить результат. Например, (20/5) / 2 = 2, но 20 / (5/2) = 8 (где использование скобок означает, что операции внутри скобок выполняются перед операциями вне скобок).
Однако деление традиционно считается левоассоциативным. То есть, если в строке несколько делений, порядок вычислений идет слева направо:
Деление право-распределительное над сложением и вычитанием в том смысле, что
a ± bc = (a ± b) / c = (a / c) ± (b / c) = ac ± bc. <\ displaystyle <\ frac
> = (a \ pm b) / c = (a / c) \ pm (b / c) = <\ frac > \ pm <\ frac >.> Это то же самое для умножения, как (a + b) × c = a × c + b × c <\ displaystyle (a + b) \ times c = a \ times c + b \ times c>. Однако деление не является лево-распределительным, так как
a b + c = a / (b + c) ≠ (a / b) + (a / c) = a c + a b b c. <\ displaystyle <\ frac > = a / (b + c) \ neq (a / b) + (a / c) = <\ frac
>. > В этом отличие от умножения, которое является как лево-распределительным, так и право-распределительным, и, следовательно, распределительным.
Обозначение
Плюс и минусы. obelus, используемый как вариант знака «минус» в отрывке из официальной норвежской формы торгового отчета под названием «Næringsoppgave 1» за 2010 налоговый год.
В алгебре и естественных науках деление часто отображается путем размещения делимое по делителю с горизонтальной линией, также называемой дробной чертой, между ними. Например, «a, разделенное на b» можно записать как:
ab <\ displaystyle <\ frac >>
, что также может быть прочитано вслух как «разделить a на b» или a над b «. Чтобы выразить деление в одной строке, нужно написать делимое (или числитель), затем косую черту, затем делитель (или знаменатель) следующим образом:
Это обычный способ указания деления в большинстве компьютерных языков программирования, так как его можно легко ввести как простую последовательность символов ASCII. Некоторое математическое программное обеспечение, такое как MATLAB и GNU Octave, позволяет записывать операнды в обратном порядке с помощью обратной косой черты в качестве оператор деления:
Типографский вариант на полпути между этими двумя формами использует солидус (дробная косая черта), но увеличивает дивиденд и снижает divisor:
Любую из этих форм можно использовать для отображения дроби. Дробь — это выражение деления, где и делимое, и делитель являются целыми числами (обычно называемыми числителем и знаменателем), и нет никакого смысла в том, что деление должно оцениваться дальше. Второй способ показать деление — использовать знак деления (÷, также известный как obelus, хотя этот термин имеет дополнительные значения), распространенный в арифметике, следующим образом:
Эта форма встречается нечасто, за исключением элементарной арифметики. ISO 80000-2 -9.6 гласит, что его не следует использовать. Этот знак деления также используется отдельно для представления самой операции деления, например, как метка на клавише калькулятора. Обелус был введен швейцарским математиком Иоганном Раном в 1659 году в немецкой алгебре. Символ ÷ используется для обозначения вычитания в некоторых европейских странах, поэтому его использование может быть неправильно понято.
В некоторых не англоязычных странах, двоеточие используется для обозначения деления:
Это обозначение было введено Готфрид Вильгельм Лейбниц в его Acta eruditorum 1684 года. Лейбниц не любил использовать отдельные символы для соотношения и деления. Однако в английском использовании двоеточие ограничивается выражением связанной концепции соотношений.
С XIX века в учебниках США используется b) a <\ displaystyle b) a>или b) a ¯ <\ displaystyle b <\ overline <) a>>> для обозначения a, разделенного на b, особенно при обсуждении деления столбиком. История этой нотации не совсем ясна, поскольку она развивалась с течением времени.
Вычисления
Ручные методы
Разделение часто вводится через понятие «совместного использования» набора объектов, например, кучу леденцов, на несколько равных частей. Распределение объектов по нескольку одновременно в каждом раунде совместного использования для каждой части приводит к идее «разбиения на части » — формы деления, при которой из самого дивиденда многократно вычитаются кратные делителя.
Позволяя вычесть больше кратных, чем позволяет частичный остаток на данном этапе, можно также разработать более гибкие методы, такие как двунаправленный вариант разбиения на части.
Более систематический и более эффективный (но также более формализованный, более основанный на правилах и более удаленный от общей целостной картины того, что достигается делением), человек, который знает таблицы умножения, может разделить два целых числа карандашом и бумагой с использованием метода короткого деления, если делитель маленький, или длинного деления, если делитель больше. Если дивиденд имеет дробную часть (выраженную как десятичная дробь ), можно продолжить алгоритм, начиная с единиц, сколько угодно. Если делитель имеет дробную часть, можно переформулировать проблему, перемещая десятичную дробь вправо в обоих числах, пока в делителе не будет дроби.
Человек может рассчитать деление с помощью счётов.
Человек может использовать таблицы логарифмов для деления двух чисел, вычитая логарифмы двух чисел, а затем ища антилогарифм результата.
Человек может рассчитать деление с помощью логарифмической линейки , совместив делитель на шкале C с делителем на шкале D. Частное можно найти на шкале D, где оно совмещено с левым индексом на шкале C. Однако ответственность за мысленное отслеживание десятичной точки лежит на пользователе.
С помощью компьютера или с помощью компьютера
Современные компьютеры вычисляют деление более быстрыми методами, чем деление в столбик, при этом более эффективные методы основываются на методах аппроксимации из численного анализа. Для деления с остатком см. Алгоритм деления.
В модульной арифметике (по модулю простого числа) и для действительных чисел ненулевые числа имеют мультипликативный обратный. В этих случаях деление на x может быть вычислено как произведение на мультипликативную обратную величину x. Этот подход часто ассоциируется с более быстрыми методами компьютерной арифметики.
Деление в разных контекстах
Евклидово деление
Деление целых чисел в компьютерной программе требует особой осторожности. Некоторые языки программирования, такие как C, обрабатывают целочисленное деление, как в случае 5 выше, поэтому ответ будет целым числом. Другие языки, такие как MATLAB и каждая система компьютерной алгебры, возвращают рациональное число в качестве ответа, как в случае 3 выше. Эти языки также предоставляют функции для получения результатов для других наблюдений, либо напрямую, либо из результата случая 3.
Имена и символы, используемые для целочисленного деления, включают div, /, \ и%. Определения различаются относительно целочисленного деления, когда делимое или делитель отрицательное: округление может быть в сторону нуля (так называемое Т-деление) или в сторону -∞ (F-деление); возможны более редкие стили — подробнее см. Операция по модулю.
Правила делимости иногда можно использовать, чтобы быстро определить, делится ли одно целое число точно на другое.
рациональных чисел
Результатом деления двух рациональных чисел является другое рациональное число, когда делитель не равен 0. Деление двух рациональных чисел p / q и r / s можно вычислить как
Все четыре величины являются целыми числами, и только p может быть 0. Это определение гарантирует, что деление является обратной операцией умножения.
действительных чисел
Деление двух действительных чисел приводит к другому действительному числу (когда делитель равен ненулевое). Он определяется так, что a / b = c тогда и только тогда, когда a = cb и b ≠ 0.
Комплексных чисел
Деление двух комплексных чисел (когда divisor отлично от нуля) приводит к другому комплексному числу, которое находится с использованием конъюгата знаменателя:
Этот процесс умножения и деления на r — is <\ displaystyle r-is>называется «реализацией» или (по аналогии) рационализацией. Все четыре величины p, q, r, s являются действительными числами, а r и s не могут быть равными 0.
Деление комплексных чисел, выраженных в полярной форме, проще, чем определение выше:
peiqreis = peiqe — isreise — это = prei (q — s). <\ displaystyle
\ over re ^ > = e ^ <- is>\ over re ^ e ^ <- is>> = e ^ .>
Опять же, все четыре величины p, q, r, s являются действительными числами, и r не может быть 0.
Многочленов
Можно определить операцию деления для многочленов в одной переменной над полем . Тогда, как и в случае с целыми числами, остается остаток. См. Евклидово деление многочленов, и, для рукописных вычислений, полиномиальное деление в столбик или синтетическое деление.
Матриц
Можно определить операция деления для матриц. Обычный способ сделать это — определить A / B = AB, где B обозначает инверсию B, но гораздо чаще AB явно записывают, чтобы избежать путаницы. поэлементное деление также может быть определено в терминах произведения Адамара.
Левое и правое деление
Поскольку матричное умножение не является коммутативным, можно также определить левое деление или так называемое обратное деление косой черты как A \ B = AB. Чтобы это было четко определено, B не обязательно существует, однако A должен существовать. Чтобы избежать путаницы, разделение, определяемое как A / B = AB, иногда в этом контексте называется разделением справа или косой чертой.
Обратите внимание, что с левым и правым делением, определенным таким образом, A / (BC) в общем случае не то же самое, что (A / B) / C, и (AB) \ C не то же самое, что A \ ( ДО Н.Э). Однако верно, что A / (BC) = (A / C) / B и (AB) \ C = B \ (A \ C).
Псевдообратная
Чтобы избежать проблем, когда A и / или B не существуют, деление также может быть определено как умножение на псевдообратное. То есть A / B = AB и A \ B = AB, где A и B обозначают псевдообратные точки A и B.
Абстрактная алгебра
В абстрактной алгебре, учитывая магму с бинарной операцией ∗ (которую можно условно назвать умножением), левое деление b на a (записанное a \ b) обычно определяется как решение x уравнения a ∗ x = b, если он существует и уникален. Точно так же правое деление b на a (обозначенное b / a) — это решение y уравнения y ∗ a = b. Деление в этом смысле не требует от ∗ каких-либо конкретных свойств (таких как коммутативность, ассоциативность или единичный элемент).
«Разделение» в смысле «аннулирования» может быть выполнено в любой магме элементом со свойством отмены . Примеры включают матричные алгебры и кватернионные алгебры. Квазигруппа — это структура, в которой всегда возможно деление, даже без элемента идентичности, и, следовательно, наоборот. В области целостности , где не каждый элемент должен иметь инверсию, деление на отменяющий элемент a по-прежнему может выполняться для элементов формы ab или ca посредством левой или правой отмены, соответственно. Если кольцо конечно и каждый ненулевой элемент является сокращаемым, то, применяя принцип голубятни, каждый ненулевой элемент кольца обратим, и возможно деление на любой ненулевой элемент.. Чтобы узнать, когда алгебры (в техническом смысле) имеют операцию деления, обратитесь к странице алгебр деления. В частности, периодичность Ботта может использоваться, чтобы показать, что любая действительная нормированная алгебра с делением должна быть изоморфна либо действительным числам R, комплексные числа C, кватернионы Hили октонионы O.
Исчисление
производная частное двух функций дается правилом частного :
Деление на ноль
Деление любого числа на ноль в большинстве математических систем не определено, потому что умножение нуля на любое конечное число всегда дает произведение, равное нулю. Ввод такого выражения в большинство калькуляторов вызывает сообщение об ошибке. Однако в некоторых математиках более высокого уровня деление на ноль возможно с помощью нулевого кольца и алгебр, таких как колеса. В этих алгебрах значение деления отличается от традиционных определений.
Целочисленная арифметика. Делим с округлением результата. Часть 1
Чем проще, на первый взгляд, задача, тем меньше разработчик вдумывается в то, как грамотно её реализовать, и допущенную ошибку, в лучшем случае, обнаруживает поздно, в худшем — не замечает вовсе. Речь пойдет об одной из таких задач, а именно, о дробном делении и о масштабировании в контроллерах, поддерживающих исключительно целочисленную арифметику.
Почему тонкостям вычислений в условиях такой арифметики разработчики прикладных программ не уделяют внимание, вопрос. Рискну только предположить, что, по всей вероятности, сказывается привычка производить вычисления на калькуляторе… Во всяком случае, с завидной регулярностью «имею счастье» лицезреть, как коллеги по цеху наступают на одни и те же грабли. Этот материал нацелен на то, чтобы те самые «грабли» нейтрализовать.
При целочисленной арифметике результат деления одного целого числа на другое состоит из двух чисел — частного и остатка. Если остаток деления отбросить, получим результат, в абсолютной величине округленный до меньшего целого.
Реализуя вычисления с дробями, этот момент частенько упускают из вида, а, упустив, получают потери в точности вычислений. Причем точность вычислений падает с ростом величины делителя. К примеру, что 53/13, что 64/13 дадут в результате 4, хотя, по факту, частное от деления второй дроби существенно ближе к 5.
Принимая во внимание то, что такие вычисления в программе могут потребоваться неоднократно, алгоритм вычислений реализуем в формате, пригодном для упаковки в подпрограмму.
Для корректного выполнения необходимых для этого промежуточных вычислений понадобится массив из пяти регистров, обозначим его условно TEMP[0..4]. Почему пять и не меньше, поясню чуть ниже.
Шаги с 3-го по 7-й могут быть вынесены в подпрограмму.
При желании, запись результата может быть произведена непосредственно суммированием TEMP[0] c TEMP[1] за пределами подпрограммы расчета. Это непринципиально. Единственное, следует иметь в виду, что при множестве однотипных расчетов вынос операции сложения в основное тело программы способен привести к возрастанию задействованного ею объема программной памяти.
Так почему же для промежуточных вычислений потребовалось целых 5 регистров? А операция суммирования остатка деления самого с собой, о чем говорилось ранее, заменена умножением остатка на два? Очень просто — для того, чтобы оперировать с неограниченным набором целых чисел.
Поясню: если поделить, к примеру, число 32767 на -32768 в остатке получим 32767, и результат его сложения несомненно выйдет за пределы диапазона integer.