Неявные правила преобразования типов в операторы С++

Я хочу лучше узнать, когда я должен бросить. Каковы правила неявного преобразования типов в С++ при добавлении, умножении и т.д. Например,

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?

et cetera...

Будет ли выражение всегда оцениваться как более точный тип? Различаются ли правила для Java? Пожалуйста, поправьте меня, если я сформулирую этот вопрос неточно.

Ответ 1

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

If either is      long          double the other is promoted to      long          double
If either is                    double the other is promoted to                    double
If either is                    float  the other is promoted to                    float
If either is long long unsigned int    the other is promoted to long long unsigned int
If either is long long          int    the other is promoted to long long          int
If either is long      unsigned int    the other is promoted to long      unsigned int
If either is long               int    the other is promoted to long               int
If either is           unsigned int    the other is promoted to           unsigned int
If either is                    int    the other is promoted to                    int
Both operands are promoted to int

Примечание. Минимальный размер операций int. Таким образом, short/char продвигается до int до выполнения операции.

Во всех ваших выражениях int продвигается до float до выполнения операции. Результатом операции является float.

int + float =>  float + float = float
int * float =>  float * float = float
float * int =>  float * float = float
int / float =>  float / float = float
float / int =>  float / float = float
int / int                     = int
int ^ float =>  <compiler error>

Ответ 2

Арифметические операции с float приводят к float.

int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int

Подробнее. Посмотрите, что говорится в разделе §5/9 стандарта С++.

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

Этот шаблон называется обычным арифметические преобразования, которые определяется следующим образом:

- Если один из операндов имеет тип long двойной, другой должен быть преобразован длинный двойной.

- В противном случае, если операнд двойной, другой должен быть преобразован в двойной.

- В противном случае, если либо операндом является float, другой преобразуется в float.

- В противном случае интегральные акции (4.5) должны выполняться на обоих операнды .54)

- Тогда, если либо операнд долгое время без знака преобразуется в unsigned long.

- В противном случае, если один операнд длинный int и другой неподписанный int, тогда если длинный int может представлять все значения беззнакового int, unsigned int преобразуется в long int; в противном случае оба операнда должны быть преобразованы в unsigned long внутр.

- В противном случае, если любой из операндов долго, другой должен быть преобразован в долго.

- В противном случае, если либо операнд является неподписанным, другое должно быть преобразован в unsigned.

[Примечание: в противном случае единственным оставшимся случаем является что оба операнда являются int]

Ответ 3

Поскольку другие ответы не говорят о правилах в С++ 11, здесь один. Из стандарта С++ 11 (черновик №3337) §5/9 (подчеркнуто отличие):

Этот шаблон называется обычными арифметическими преобразованиями, которые определяются следующим образом:

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

- Если один из операндов имеет тип long double, другой должен быть преобразован в long double.

- В противном случае, если один из операндов является двойным, другой должен быть преобразован в двойной.

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

- В противном случае интегральные продвижения выполняются для обоих операндов. Затем к повышенным операндам применяются следующие правила:

  - Если оба операнда имеют одинаковый тип, дальнейшее преобразование не требуется.

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

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

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

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

Смотрите здесь для списка, который часто обновляется.

Ответ 4

Этот ответ во многом определяется комментарием @RafałDowgird:

"Минимальный размер операций - int". - Это было бы очень странно (что относительно архитектур, которые эффективно поддерживают char/short операции?) Действительно ли это в спецификации С++?

Имейте в виду, что стандарт С++ имеет всеохватывающее правило "как есть". См. Раздел 1.8: Выполнение программы:

3) Это положение иногда называют правилом "как есть", поскольку реализация может свободно игнорировать любые требования Стандарта до тех пор, пока результат будет таким, как если бы требование было соблюдено, насколько это возможно как это можно определить из наблюдаемого поведения программы.

Компилятор не может установить размер int размером 8 бит, даже если он был самым быстрым, так как в стандарте содержится минимум 16 бит int.

Следовательно, в случае теоретического компьютера с сверхбыстрыми 8-битными операциями может иметь значение неявное продвижение до int для арифметики. Однако для многих операций вы не можете определить, действительно ли компилятор выполнял операции с точностью int, а затем преобразовывался в char для хранения в вашей переменной или если операции выполнялись в char все время.

Например, рассмотрим unsigned char = unsigned char + unsigned char + unsigned char, где добавление будет переполняться (допустим, чтобы значение 200 для каждого). Если вы повысились до int, вы получите 600, что затем будет неявно опущено в unsigned char, которое будет обертывать по модулю 256, что даст окончательный результат 88. Если вы не сделали таких рекламных акций, вы бы должны обернуться между первыми двумя дополнениями, что уменьшит проблему с 200 + 200 + 200 до 144 + 200, что составляет 344, что уменьшится до 88. Другими словами, программа не знает разницы, поэтому компилятор свободен для игнорировать мандат на выполнение промежуточных операций в int, если операнды имеют более низкий рейтинг, чем int.

Это вообще относится к сложениям, вычитанию и умножению. Это не верно в общем случае для деления или модуля.

Ответ 5

Если вы исключаете неподписанные типы, иерархия: подписан char, короткий, int, long, long long, float, двойной, длинный двойной. Во-первых, все, что приходит перед int в выше будет преобразован в int. Затем, в двоичной операции, более низкий ранжированный тип будет преобразован в более высокий, а результаты будут типом высшего. (Вы заметите, что из иерархия, в любое время с плавающей точкой и интегральным типом участвующий, интегральный тип будет преобразован в плавающий точечный тип.)

Unsigned немного усложняет ситуацию: он нарушает рейтинг и части ранжирования становятся реализацией. Из-за это, лучше не смешивать подписанные и неподписанные в одном и том же выражение. (Большинство экспертов на C++, похоже, избегают побитовые операции. То есть, по крайней мере, что Страуструп рекомендует.)

Ответ 6

My решение в problem получил WA (неправильный ответ), то я изменил один из int на long long int и дал AC (accept). Раньше я пытался сделать long long int += int * int, и после того, как исправил его до long long int += long long int * int. Googling я придумал,

1. Арифметические преобразования

Условия преобразования типов:

Условия Met --- > Конверсия

  • Оба операнда имеют тип длинный двойной. --- > Другой операнд преобразуется в тип длинный двойной.

  • Предыдущее условие не выполнено, и оба операнда имеют тип double. --- > Другой операнд преобразуется в тип double.

  • Предыдущие условия не выполняются, и оба операнда имеют тип float. --- > Другой операнд преобразуется в тип float.

  • Предыдущие условия не выполняются (ни один из операндов не имеет плавающих типов). --- > Интегральные рекламные акции выполняются по операндам следующим образом:

    • Если любой из операндов имеет тип unsigned long, другой операнд преобразуется в тип без знака long.
    • Если предыдущее условие не выполнено, и если один из операндов имеет тип long, а другой тип unsigned int, оба операнда преобразуются в тип без знака.
    • Если предыдущие два условия не выполняются, и если один из операндов имеет тип long, другой операнд преобразуется в тип long.
    • Если предыдущие три условия не выполняются и если один из операндов имеет тип unsigned int, другой операнд преобразуется в тип unsigned int.
    • Если ни одно из предыдущих условий не выполняется, оба операнда преобразуются в тип int.

2. Правила преобразования целых чисел

  • Целочисленные акции:

Целочисленные типы, меньшие, чем int, продвигаются, когда на них выполняется операция. Если все значения исходного типа могут быть представлены как int, значение меньшего типа преобразуется в int; в противном случае он преобразуется в unsigned int. Целочисленные акции применяются как часть обычных арифметических преобразований к некоторым выражениям аргументов; операнды унарных +, - и ~ операторов; и операнды операторов сдвига.

  • Integer ранг:

    • Никакие два знаковых целочисленных типа не должны иметь одинаковый ранг, даже если они имеют одинаковое представление.
    • Ранг знакового целочисленного типа должен быть больше ранга любого целочисленного типа со знаком с меньшей точностью.
    • Ранг long long int должен быть больше ранга long int, который должен быть больше ранга int, который должен быть больше ранга short int, который должен быть больше, чем ранг signed char.
    • Ранг любого беззнакового целочисленного типа должен быть равен рану соответствующего знакового целочисленного типа, если он есть.
    • Ранг любого стандартного целочисленного типа должен быть больше ранга любого расширенного целочисленного типа с той же шириной.
    • Ранг char должен быть равен рангам signed char и unsigned char.
    • Ранг любого расширенного целочисленного типа со знаком, связанного с другим расширенным типом со знаком целочисленного типа с той же точностью, определяется реализацией, но по-прежнему подчиняется другим правилам определения целочисленного ранга преобразования.
    • Для всех целых типов T1, T2 и T3, если T1 имеет больший ранг, чем T2, а T2 имеет больший ранг, чем T3, то T1 имеет больший ранг, чем T3.
  • Обычные арифметические преобразования:

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

Ответ 7

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

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

Другое отличие связано с возможностью типа. Например, выражение, включающее int и long int, будет иметь тип long long.

Ответ 8

Целая глава 4 рассказывает о конверсиях, но я думаю, вы должны быть в основном заинтересованы в них:

4.5 Интегральные акции [Conv.prom]
Rvalue типа char, подписанный char, unsigned char, short int или unsigned short int может быть преобразован в rvalue типа int, если int может представлять все значения типа источника;
Другие- мудрый, исходное значение rvalue может быть преобразовано в rvalue типа unsigned int.
Rvalue типа wchar_t (3.9.1) или тип перечисления (7.2) можно преобразовать в значение r первого следующих типов, которые могут представлять все значения его базового типа: int, unsigned int,
долго или без знака.
Rvalue для целочисленного битового поля (9.6) можно преобразовать в r-значение типа int, если int может представлять все значения битового поля; в противном случае он может быть преобразован в unsigned int, если unsigned int может отображаться resent все значения бит-поля. Если бит-поле еще больше, к нему не применяется целая реклама. Если бит-поле имеет нумерованный тип, он рассматривается как любое другое значение этого типа для целей продвижения.
Rvalue типа bool может быть преобразовано в rvalue типа int, при этом false становится нулевым и истинным
становится одним.
Эти преобразования называются интегральными акциями.

4.6 Плавающая точка продвижения [Conv.fpprom]
Rvalue типа float может быть преобразовано в rvalue типа double. Значение не изменяется.
Это преобразование называется продвижением с плавающей запятой.

Следовательно, все преобразования, включающие float - результат - float.

Только тот, который включает оба int - результат: int: int/int = int

Ответ 9

Протест!

Конверсии происходят слева направо.

Попробуйте следующее:

int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0