Как компьютер делит числа

Обновлено: 02.07.2024

Только после того, как вы узнаете, что находится под капотом, ваши навыки программирования расцветут; Итак, взгляните на то, как сначала работали компьютеры и как они развивались с течением времени.

Эта глава из книги

Эта глава из книги

Эта глава из книги 

Группа Sales Force Automation вашей компании имеет очень большую базу данных размером 50 ГБ. Данные разделены между тремя файлами из соображений производительности: DBFile1, DBFile2 и DBFile3. Вам разрешено не более 60 минут простоя этой базы данных.

У вас есть следующий график резервного копирования базы данных:

Тип резервного копированияДниВремя
Полное резервное копирование Понедельник2:00 AM
Полное резервное копирование файлов DBFILE1Вторник2: 00:00
Полное резервное копирование файлов DBFILE2Среда2:00
Полное резервное копирование файла DBFILE3Четверг2:00 AM
Резервное копирование журнала транзакций Ежедневно11:00
Резервное копирование журнала транзакцийЕжедневно19:00

В среду в 9:00 физический носитель файла DBFile1 был поврежден. Какие шаги вы предпримете для восстановления базы данных за отведенное время? Вы не можете создать резервную копию текущего журнала транзакций.

С этой главой вы сможете вступить в ряды немногих, гордых, людей завтрашнего дня, развивая понимание нескольких языков программирования. В этой главе основное внимание уделяется более ранним языкам программирования, некоторые из которых используются до сих пор. Вы узнаете, как появились языки программирования и как они развивались на протяжении многих лет.

Основные моменты этой главы включают следующее:

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

Код ASCII определяет двоичные шаблоны для каждого символа, представляемого компьютером.

Самые ранние компьютеры программировались с помощью проводов.

FORTRAN и COBOL многие годы были предпочтительными языками для науки и бизнеса.

На протяжении многих лет правительство предпочитало использовать ADA.

Хранение программ и данных

Когда вы печатаете на клавиатуре, как вы думаете, что происходит, когда вы нажимаете клавиши? Уходит ли буква A куда-то в память компьютера, когда вы нажимаете клавишу A? Так и должно быть, иначе компьютер никогда не сможет запомнить содержимое вашей программы. Компьютер хранит A, но не в том формате, в котором вы могли бы ожидать. Компьютер хранит только представление буквы A. Во всех смыслах буква A находится в памяти, но не выглядит так, как вы думаете.

Причина, по которой требуется восемь переключателей, заключается в том, что если бы их было меньше, то не хватило бы комбинаций включенных и выключенных состояний для представления всех возможных символов (прописных, строчных, цифр и специальных символов, таких как %, ^, и *).

Помните, что ваш компьютер — это не что иное, как тысячи выключателей, которые включают и выключают электричество. Каждый символ на вашем компьютере представлен комбинацией переключателей включения и выключения. Программисты обычно называют выключатель «1» (единица), а «выкл» — 0 (ноль). Поскольку эти переключатели имеют только два значения, программисты называют 0 и 1 двоичными цифрами или битами для краткости. Всего на каждый символ в вашем компьютере приходится восемь бит, и восемь бит известны как байт. Таким образом, для представления каждого символа памяти требуется восемь битов (восемь переключателей включения и выключения), и, следовательно, символ представляет собой байт.

Несколько лет назад кто-то записал различные комбинации восьми единиц и нулей от 00000000 до 11111111 и присвоил каждой из них уникальный символ. Таблица символов была стандартизирована и сегодня известна как Таблица ASCII (произносится как аск-и, поэтому, если вы не знаете-и, вы можете использовать ASCII). Таблица 3.1 показывает частичный список таблицы ASCII. ASCII расшифровывается как Американский стандартный код для обмена информацией.

Таблица 3.1. Значения ASCII представляют символы

Каждому из значений ASCII соответствует соответствующее десятичное число. Эти значения показаны справа от восьмибитных значений в таблице 3.1. Следовательно, даже если компьютер представляет символ ? как 00111111 (два выключателя с шестью включенными), вы можете с помощью программирования обратиться к этому значению ASCII как 63, и ваш компьютер будет знать, что вы имеете в виду 00111111. Одно из преимуществ языков программирования высокого уровня заключается в том, что они часто позволяют вам используйте более простые (для людей) десятичные значения, а язык программирования преобразует значение в восьмибитное двоичное значение, используемое внутри компьютера.

Как видно из значений ASCII в таблице 3.1, каждый символ в компьютере, будь то прописные и строчные буквы, и даже пробел, имеет свое собственное уникальное значение ASCII.Уникальный код ASCII — это единственный способ, с помощью которого компьютер может различать символы. Некоторые мейнфреймы используют аналогичную систему, которая называется таблица EBCDIC, произносится как eb-se-dik.

Вспомните внутреннее хранилище отдельных символов, описанное ранее в этом разделе. Когда вы нажимаете букву А, эта А не сохраняется в вашем компьютере; вместо этого сохраняется ASCII-значение A. Как видно из значений ASCII в предыдущей таблице, буква A представлена ​​как 01000001 (все восемь переключателей, кроме двух, выключены в каждом байте памяти, содержащем букву A).

Как показано на рис. 3.1, когда вы нажимаете букву A на клавиатуре, в память попадает не буква A, а значение ASCII 01000001. Компьютер сохраняет этот шаблон включения и выключения в этой ячейке памяти до тех пор, пока там остается буква А. Что касается вас, то в памяти буква А остается как буква А, но теперь вы точно знаете, что происходит. Если вы печатаете программу, которую только что набрали, и компьютер готов напечатать символ, хранящийся в этой ячейке памяти, центральный процессор компьютера отправляет код ASCII для буквы A на принтер. Непосредственно перед печатью принтер знает, что его вывод должен быть удобочитаемым для людей, поэтому он ищет 01000001 в своей собственной таблице ASCII и печатает букву А на бумаге. С того момента, как буква А покинула клавиатуру, и до момента, когда она была напечатана, это была вовсе не буква А, а просто комбинация восьми единиц и нулей, представляющая букву А.

Таблица ASCII не сильно отличается от других типов кодированных таблиц, о которых вы, возможно, слышали. Азбука Морзе представляет собой таблицу представлений букв алфавита. Вместо единиц и нулей код использует комбинации тире и точек для представления символов. Штрихи и точки обозначают длину радиосигналов, которые люди отправляют или принимают. Буквы SOS представлены ТОЧКА-ТОЧКА-ТОЧКА ТИРЕ-ТИРЕ-ТИРЕ ТОЧКА-ТОЧКА-ТОЧКА.

Как происходит деление внутри цифровых компьютеров? Каков алгоритм для этого?

Я много искал в Google, но не получил удовлетворительных результатов. Предоставьте очень четкий алгоритм/блок-схему для алгоритма деления с образцом иллюстрации.

\$\begingroup\$ @program-o-steve Деление в АЛУ — сложная операция. Вы не получите «простую» блок-схему. \$\конечная группа\$

\$\begingroup\$ @ Леон Хеллер Думаю, это не . включая электронику, физические вычисления. \$\endgroup\$

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

\$\begingroup\$ @LeonHeller Я обычно соглашаюсь с вопросами, которые вы хотите закрыть, но проектирование процессора во многом является вопросом электротехники. В этом вопросе может понадобиться некоторая помощь, чтобы сделать его более ясным в отношении того, что требуется (например, о чем спрашивает konsalik), но это не делает его не по теме. \$\конечная группа\$

5 ответов 5

Алгоритмы деления в цифровых проектах можно разделить на две основные категории. Медленное деление и быстрое деление.

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

Медленное деление

Простейшие медленные методы работают следующим образом: из числителя вычитается знаменатель. Делайте это рекурсивно с результатом каждого вычитания, пока остаток не станет меньше знаменателя. Количество итераций – это целое частное, а количество оставшихся – это остаток.

Таким образом, ответ равен 2 с остатком 1. Чтобы сделать этот ответ более актуальным, вот некоторая предыстория. Двоичное вычитание сложением минуса выполняется, например: 7 - 3 = 7 + (-3). Это достигается с помощью дополнения до двух. Каждое двоичное число добавляется с помощью серии полных сумматоров:

введите здесь описание изображения

Где каждый 1-битный полный сумматор реализуется следующим образом:

введите здесь описание изображения

Быстрый дивизион

Хотя более медленный метод деления прост для понимания, он требует повторяющихся итераций. Существуют различные «быстрые» алгоритмы, но все они основаны на оценке.

Рассмотрите метод Гольдшмидта:

Я буду использовать следующее: $$Q = \frac$$

Этот метод работает следующим образом:

  1. Умножьте N и D на дробь F таким образом, чтобы D приблизилось к 1.
  2. Когда D приближается к 1, N приближается к Q

В этом методе используется двоичное умножение посредством итеративного сложения, которое также используется в современных процессорах AMD.

\$\begingroup\$ Некоторые блок-схемы для вариаций «медленного» метода (реализованного в сборке на микропроцессорах без аппаратного разделения, но все же полезного) приведены в приложении Atmel к AVR200. \$\конечная группа\$

\$\begingroup\$ не могли бы вы привести иллюстрацию метода деления Гольдшмидта. Также приведенная здесь блок-схема является примером медленного деления? \$\конечная группа\$

\$\begingroup\$ что это за метод, в котором мы должны неоднократно сдвигать делимое влево? \$\конечная группа\$

\$\begingroup\$ @program-o-steve Вот небольшая иллюстрация: найдите 22/7 (приближение пи). Во-первых, умножьте верх и низ на 0,1, чтобы получить: 2,2/0,7. Умножьте снова, используя 1,3, что даст: 2,86/0,91. Используя 1,09, вы получите: 3,1174/0,9919 1,008, получите: 3,1423393/0,9998352. Продолжайте, скоро вы получите ОКОНЧАТЕЛЬНЫЙ ОТВЕТ 3,1428571/ 1.000000. \$\конечная группа\$

\$\begingroup\$ Сравнить, вычесть и сдвинуть — это алгоритм деления, связанный с алгоритмом умножения сложения и сдвига. Я реализовал это на многих ранних микропроцессорах, и его преимущество заключается в том, что затрачиваемое время не зависит от данных. \$\конечная группа\$

Аппаратное обеспечение для деления с плавающей запятой является частью логического устройства, которое также выполняет умножение; имеется аппаратный модуль умножителя. Числа с плавающей запятой, например A и B, делятся (образуя A/B) на

  1. разложение чисел с плавающей запятой на знак (+1 или -1), мантиссу ("a" и "b" и экспоненты (двоичный целочисленный тип)
  2. знак результата равен (+1), если оба знака совпадают, иначе (-1)
  3. показатели вычитаются (показатель степени B вычитается из показателя степени A), чтобы сформировать показатель степени результата

мантиссы (двоичные разряды чисел) — это двоичные числа с фиксированной запятой от 1/2 до 1; это означает, что первая цифра после двоичной точки — «1», за которой следуют нули и единицы. в качестве первого шага таблица поиска находит обратное значение с точностью до шести битов (есть только 32 возможности, это маленькая таблица)

Чтобы начать вычисление a/b, выполните два умножения $$ = \over b * reciprocal(b)> $$ и обратите внимание, что шестибитная точность подразумевает, что знаменатель результата очень близок к 1 (до пяти или больше двоичных разрядов).

Интересно, что старая ошибка деления Pentium (очень заслуживающая внимания в 1994 г.) была вызвана ошибкой печати, которая приводила к ошибочным значениям обратной таблицы для шага (4). Ранняя статья «Метод деления с использованием параллельного множителя», Доменико Феррари, IEEE Trans. Электрон. вычисл. EC-16/224-228 (1967) описывает метод, как и «IBM System/360 Model 91: Floating-Point Execution Unit» IBM J. Res. Дев. 11: 34–53 (1967).

\$\begingroup\$ Спасибо, это потрясающий ответ. Не могли бы вы также объяснить алгоритм быстрого целочисленного деления в том же духе? \$\конечная группа\$

Существуют очень разные методы деления, в зависимости от обрабатываемых чисел. Для целых чисел метод сдвига и вычитания, предложенный другими, будет работать нормально. Однако для чисел с плавающей запятой может быть быстрее сначала вычислить обратную величину знаменателя, а затем умножить ее на числитель.

Вычисление обратной величины знаменателя не так уж плохо; это делается путем уточнения последовательных приближений. Пусть g будет вашим предположением для 1/d. Для более точного предположения используйте g'=g(2-gd). Это сходится квадратично, поэтому вы удваиваете цифры точности при каждом улучшении.

Пример: вычислить обратную величину 3,5.

Ваше первоначальное предположение равно 0,3. Вы вычисляете 0,3 * 3,5 = 1,15. Ваше скорректированное предположение: 0,3 * (2 - 1,15) = 0,285. Уже совсем близко! Повторите процесс, и вы получите 0,2857125, а третья попытка даст 0,2857142857.

Есть несколько сокращений. В числах с плавающей запятой вы можете извлекать степени десяти или степени двойки, в зависимости от базы счисления вашей машины. И для ускорения за счет большего использования памяти вы можете использовать предварительно вычисленную таблицу для чисел в диапазоне от 1 до b (где b — ваша числовая база), чтобы получить предположение, которое сразу же близко к требуемому обратному и сохраните один или два шага уточнения.

Имейте в виду, что, как и в случае с умножением и смущением Колмогорова в 1960 году его учеником Анатолием Карацубой, вы никогда не знаете, когда будет найден более быстрый или лучший метод. Никогда не отказывайтесь от своего любопытства.

Косая черта

<р>1. В математике деление обозначается клавишей косой черты (/) на клавиатуре. Он описывает, сколько раз одно число переходит в другое число. Например, 10 разделить на 2 (10/2) равно 5.

Для деления чисел на компьютере или смартфоне можно использовать калькулятор или электронную таблицу.

Где ключ разделения?

Косая черта или разделитель находятся на клавише рядом с правым Shift (та же клавиша, что и вопросительный знак). Если ваша клавиатура имеет цифровую клавиатуру, есть две клавиши косой черты или символа разделения.Дополнительную информацию о косой черте см. на странице косой черты.

Как разделить в электронной таблице

Чтобы разделить в программе для работы с электронными таблицами, такой как Microsoft Excel, вы можете использовать косую черту и ячейки, которые вы хотите разделить в формуле, как показано ниже.

Поместив эту формулу в ячейку C1, вы увидите общее значение в ячейке A1, деленное на значение в B1. Если значения ячеек A1 или B1 изменятся, общее значение в ячейке C1 также изменится автоматически.

В Excel нет функции "разделить". Другими словами, вы не можете ввести =DIVIDE(A1/B1).

Как делить в компьютерном программировании

В компьютерном программировании косая черта может разделять число или числа, хранящиеся в переменной, как показано в следующем коде Perl.

При запуске приведенного выше сценария на экране отображается сообщение "Вы получите 3, если разделите 15 на 5".

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

Как создать знак разделения в HTML

Чтобы создать знак разделения ( ÷ ) в HTML, вы можете использовать любой из следующих кодов.

Дополнительная информация

<р>2. Делитель может описать человека или вещь, которая разделяет. Разделитель также описывает один или несколько символов, разделяющих текст. Например, символ @ (знак at) или @ используется в адресе электронной почты в качестве разделителя. Он отделяет уникальное имя или псевдоним человека от имени домена, на котором работает служба электронной почты. Другое слово для этого типа разделителя — разделитель.

Нам (людям) требуется больше времени, чтобы умножить, сложить, разделить и вычесть два больших числа, чем два маленьких числа.

Занимает ли компьютер больше времени, чтобы умножить 5 * 2, чем, скажем, 51234 * 987654, или операция выполняется за такое же время?

Что делать с двумя числами, превышающими размер слова процессора (например, два 128-битных числа)?

Я думаю, что они имеют одинаковую сложность, поскольку как ЦП узнает, большое это число или мало? Ему все равно придется пережевывать каждый бит (независимо от того, равны ли старшие биты 0).

2 ответа 2

Предполагая, что вас в основном интересует семейство x86, было время, когда время умножения зависело от операндов. Это было в прошлом веке — процессоры до 80486 включительно. Начиная с Pentium, imul всегда выполнял определенное количество циклов, независимо от его ввода.

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

Инструкции с плавающей запятой часто могут занимать переменное время, если учитывать также "странный ввод", например денормализацию.

Зависит от типа ввода. Для примитивов, изначально поддерживаемых ЦП, таких как умножение 64-битных чисел на 64-битном ЦП: нет, это атомарные операции, которые всегда занимают одинаковое количество времени. Для непримитивных типов данных, таких как BigInteger в Java или сопоставимых библиотечных классов в других языках: да, это больше не атомарные операции и, следовательно, различаются по количеству требуемого времени в зависимости от размера операндов.

Умножение примитивов всегда занимает одинаковое количество времени по простой причине: операция построена жестко, без какого-либо условного выполнения, и всегда будет повторять все 64 бита на 64-битном ЦП, независимо от того, имеет ли вход только 5 бит. или занимает все 64 бита. То же самое относится к архитектурам для любого другого количества битов.

EDIT:
Как заявил @nwellnhof: некоторые инструкции действительно содержат ветвление, например, арифметику с плавающей запятой. Обычно эти инструкции основаны на микрокоде и поэтому не могут считаться атомарными инструкциями в более узком смысле.


Я знаю, что можно выполнять умножение и деление, используя только вычитание и сложение, это основа всех вычислений. Компьютеры используют только выкл/вкл, 0/1 и т. д. Итак, мой вопрос: как это работает математически?


Как же тогда компьютер будет выражать числа с плавающей запятой?

Секрет математики заключается в том, что существует только одна математическая операция, и все остальные операции могут быть выражены через эту операцию: сложение. Вычитание, умножение, деление, возведение в степень, логарифмирование, факториал, суммирование, интегрирование, дифференцирование и т. д. Все это просто "объединить".

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

Двоичная (с основанием 2) математика ничем не отличается от десятичной (с основанием 10). Единственное отличие состоит в том, что двоичная математика состоит из 2 цифр, а не из 10 цифр десятичной математики.

Во-первых, вы не упомянули об одной операции, которую может выполнять компьютер. Сдвиг. Сдвиг просто перемещает каждое число на единицу влево или вправо (сдвиг влево и сдвиг вправо). Это равносильно делению или умножению на 2.

Что ж, начнем с самого простого.

Умножение — это многократное сложение. 3 * 2 = 3 + 3. Это просто сложение числа, которое может сделать компьютер. Вы можете сделать это немного быстрее, добавив несколько смен. Если вы хотите умножить на 10, вы можете просто сделать два сдвига влево (умножить на 2*2), добавить исходное число один раз (так что теперь у вас есть число 5 раз) и еще один сдвиг влево.

Деление можно выполнять как многократное вычитание. 15 / 3 -> 15 - 3 - 3 - 3 -3 -3 = 0. Всего 5 троек, поэтому 15/3 = 5. Если это не подходит (14/3), это не намного сложнее. Вы начинаете с той же процедуры, пока не достигнете чего-то меньшего, чем делитель (в данном случае 14). Это дает нам 4 3s. Затем вы добавляете точку, так как мы знаем, что вы не можете вместить еще целых 3 (у нас осталось 2). затем мы просто добавляем ноль и начинаем снова. 20 - 3-3-3-3-3-3 = 6 троек, а остаток 2. Итак, 4,6. И затем мы продолжаем, пока не получим требуемую точность или остаток не будет равен 0 (4,6666..).

Однако это медленно. Таким образом, современные компьютеры используют более быстрые (но трудные для понимания) алгоритмы. Один из самых простых способов выполнить деление — это просто предварительно вычислить некоторые общие обратные числа, а затем просто умножить их (обратное значение N равно 1/N). Если вы используете обратные числа, делимое которых равно 2 n, вы можете просто использовать для них сдвиг вправо, и вы упростите все это до нескольких сдвигов вправо и некоторых умножений. У вас есть еще несколько продвинутых алгоритмов, но я не буду в них вдаваться.

Наконец у вас есть аппаратные множители. Они на самом деле выполняют умножение прямо на аппаратном уровне, без использования сдвига и сложения. Однако, поскольку я не люблю оборудование, я понятия не имею, как они это делают.

Читайте также: