Целое число против плавающего деления -> Кто отвечает за предоставление результата? - PullRequest
7 голосов
/ 15 августа 2010

Я некоторое время программировал на C ++, но внезапно обнаружил сомнения и хотел уточнить с сообществом Stackoverflow.

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

Но кто несет ответственность за обеспечение этого результата?Это компилятор или инструкция DIV?

Ответы [ 6 ]

12 голосов
/ 15 августа 2010

Это зависит от того, есть ли в вашей архитектуре инструкция a DIV. Если в вашей архитектуре есть как целочисленные, так и команды деления с плавающей точкой, компилятор выдаст правильную инструкцию для случая, указанного в коде. Языковой стандарт определяет правила для продвижения типов и то, следует ли использовать целочисленное или с плавающей точкой деление в каждой возможной ситуации.

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

3 голосов
/ 15 августа 2010

Инструкции аппаратного деления почти никогда не включают преобразование между целым числом и плавающей запятой. Если вы вообще получаете инструкции деления (иногда они пропускаются, потому что схема деления большая и сложная), они практически наверняка будут «делить int на int, производить int» и «делить float на float, производить float» , Как правило, и вход, и выход имеют одинаковый размер.

Компилятор отвечает за сборку любой операции, написанной в исходном коде, поверх этих примитивов. Например, в C, если вы разделите число с плавающей точкой на int, компилятор сгенерирует преобразование типа int в float, а затем разделит число с плавающей точкой.

(Причудливые исключения существуют. Я не знаю, но я бы не сказал, что в VAX есть инструкции типа «разделяемое число с плавающей точкой». В Itanium действительно нет инструкции деления, но это не так. «Помощник деления» был только для числа с плавающей запятой, вы должны были подделать целочисленное деление поверх деления с плавающей запятой!)

3 голосов
/ 15 августа 2010

Компилятор решит во время компиляции, какая форма разделения требуется, основываясь на типах используемых переменных - в конце дня будет задействована инструкция DIV (или FDIV) той или иной формы.

1 голос
/ 15 августа 2010

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

Когда вы программируете на языке программирования [X], компилятор [X] несет исключительную ответственность за создание программы, которая делает то, что вы описали в исходном коде .

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

Но это всегда до компилятора. Ваша программа на C ++ не имеет какого-либо эффекта, если она не интерпретируется в соответствии со стандартом C ++. Если вы интерпретируете его как простой текстовый файл, он ничего не делает . Если ваш компилятор интерпретирует его как программу на Java, он захлебнется и отклонит его.

А инструкция DIV ничего не знает о стандарте C ++. Компилятор C ++, с другой стороны, написан с единственной целью понять стандарт C ++ и преобразовать код в соответствии с ним.

Компилятор всегда отвечает.

1 голос
/ 15 августа 2010

Одним из наиболее важных правил в стандарте C ++ является правило «как будто»:

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

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

Он также может:

  1. Замените операцию на операцию сдвига битов, если это уместно и, вероятно, будет быстрее.
  2. Замените операцию на литерал, если он вычисляется во время компиляции, или присваивание, если, например, при обработке х / у он можетво время компиляции будет показано, что у всегда будет 1.
  3. Замените операцию на исключение, если во время компиляции можно показать, что это всегда будет целочисленное деление на ноль.
0 голосов
/ 15 августа 2010

Практически

Стандарт C99 определяет «Когда делятся целые числа, результат оператора / является алгебраическим частным с любой дробной частью отбрасывается ". И добавляет в сноске, что" это часто называют "усечением до нуля".

История

Исторически, языковая спецификация ответственна.

Pascal определяет свои операторы , так что использование / для деления всегда возвращает real (даже если вы используете его для деления 2 целых чисел), и если вы хотите разделить целые числа и получить целое В результате вместо этого вы используете оператор div. (Visual Basic имеет аналогичное различие и использует оператор \ для целочисленного деления, которое возвращает целочисленный результат.)

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

...