2010-08-15 3 views
7

Я некоторое время программировал на C++, но внезапно возникло сомнение и хотел уточнить сообщество Stackoverflow.Integer vs floating division -> Кто несет ответственность за предоставление результата?

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

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

+1

Вы делите константы или переменные? –

ответ

3

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

+1

Если переменные не являются константами времени компиляции, в этом случае компилятор «возьмет на себя ответственность» и никаких инструкций не будет создано. – Potatoswatter

+0

@Potatoswatter: Не совсем верно; компилятор ДОЛЖЕН оценить интегральные константные выражения и МОЖЕТ оценить другие постоянные выражения. То есть 'float x = 1.0/3.0' может быть оценен компилятором, или это может привести к выбору FDIV-компилятора. – MSalters

11

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

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

3

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

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

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

+0

Хех. Что касается «сумасшедших исключений», как вы их называете, вы, вероятно, использовали его сейчас, чтобы написать этот ответ. Инструкция x86 (или более точно x87) для * делить float на int * называется FIDIV. – slacker

+1

И это не единственный момент, когда wackiness x86 ставит VAX в позор :). – slacker

+0

Hah! Ну, это будет x87. Они не делали ничего нормального с этой штукой. – zwol

0

Практически

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

История

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

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

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

1

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

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

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

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

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

Может ли он отказаться от компиляции, если бы во время компиляции можно было вывести, что фактор всегда будет нулевым, или это является законным для полностью совместимой программы на языке C, содержащей инструкцию типа x = 1/(x-x); если такая инструкция никогда не выполняется? – supercat

+0

@supercat: Это совершенно законно. Это * выполнение * деления на ноль, которое вызывает неопределенное поведение. – slacker

+1

@supercat, если вы хотите создать программу, которая всегда будет ошибкой, это ваш бизнес! В конце концов, трудно научить людей ошибкам без них (хотя на некоторых языках вам нужно делать такие вещи, как 'if (true == false)', чтобы обмануть компиляторы, позволяя вам скомпилировать). Разумеется, было бы разумно и полезно, чтобы компилятор подготовил нестандартное предупреждение. –

1

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

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

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

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

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

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

Смежные вопросы