Каковы пределы диапазона int64_t на x86? - PullRequest
0 голосов
/ 10 октября 2019

Тестирование некоторых целочисленных умножений на x86.

int32_t a = 2097152;
int64_t b = a * a;

Почему приведенное выше b оценивается как ноль?

Ответы [ 3 ]

7 голосов
/ 10 октября 2019

Каковы пределы диапазона int64_t для x86?

C11 стандарт 7.20.2.1 говорит [-2^64; 2^64-1], что эквивалентно [-9223372036854775808;9223372036854775807] Вы можете получить егопечатая INT64_MAX и INT64_MIN.

Почему приведенный выше b оценивается как ноль?

Поскольку повышение не происходит до тех пор, пока не будет оценено умножение. Результат a*a имеет тип int32_t, и когда вы переполняете целое число со знаком, вы вызываете неопределенное поведение. По сути, вы делаете следующее:

int32_t a = 2097152;
int32_t tmp = a * a;
int64_t b = tmp;

Вы можете получить желаемый результат с помощью:

int32_t a = 2097152;
int64_t b = (int64_t) a * a;
4 голосов
/ 10 октября 2019

int64_t ограничения не имеют значения в вашем примере, так как тип b входит в игру только после , вычисляется выражение a * a, и урон уже нанесен.

При выполнении арифметики выполняются «обычные арифметические преобразования», т. Е. Значения преобразуются в общий тип, который по крайней мере int;в этом случае int32_t, вероятно, уже является int под капотом, поэтому два значения остаются без изменений, и выполняется 32-битное умножение. Это переполняет диапазон int32_t, с результатом, который вы можете видеть (обратите внимание, что переполнение со знаком на самом деле неопределенное поведение).

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

int64_t b = ((int64_t)a) * a;
4 голосов
/ 10 октября 2019

Поскольку вы умножаете два 32-битных значения и получаете 32-битный результат.

Таким образом, на самом деле вы получаете (a * a) % 2^32
, так как
2097152 * 2097152 = 4398046511104 = 0x40000000000
вы получаете часть 0x00000000вашего результата.

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

int64_t b = (int64_t)a * a;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...