#c
#c
Вопрос:
Я пробую приведенный ниже код:
UINT a = 32768;
UINT b = 32768;
UINT64 c = a * b * 4; // c = 0, overflow...;
UINT64 d = (UINT64)a * (UINT64)b * 4; // d = 4294967296, the right answer;
почему UINT64 c = a * b * 4 будет переполнением?
Я думаю, что a * b * 4 сначала сохранит значение temp UINT, а затем присвоит параметру c ? Правильно ли это?
Я хочу поискать в Google какую-нибудь подсказку, но я не знаю, какое ключевое слово мне следует использовать.
Спасибо
Комментарии:
2. Ваше предположение верно. Вся операция не является атомарной.
3. Это помогло бы, если бы вы использовали стандартные типы. Что такое UINT?
4. И
uint8
? И как этоUINT
соотносится сuint8
и32768
?
Ответ №1:
UINT a = 32768;
UINT b = 32768;
UINT64 c = a * b * 4;
вычисляется как
UINT a = (UINT) 32768;
UINT b = (UINT) 32768;
UINT64 c = (UINT) a * (UINT) b * (int) 4;
Когда UINT
недостаточно места для хранения UINT*UINT
, вы получаете переполнение.
Вы можете исправить это, приведя один из UINT
s к UINT64
подобному:
UINT64 c = (UINT64) a * b * 4;
Ответ №2:
По той же причине, по которой
double x=1/2;
будет равно 0, но
double y=double(1)/2;
будет 0.5
.
Если вы не принудительно приведете один из ваших операндов к желаемому конечному типу, все будет вычислено с наибольшей точностью любого из операндов и только после этого преобразовано в целевой тип.
В вашем случае все вычисляется с точностью до 32 бит, переполнение происходит до преобразования в 64 бита.
Ответ №3:
В uint64 c его правая часть автоматически присваивается как uint, потому что A и B оба являются uint, после чего он присваивает ответ c (уже переполненный). Чтобы убедиться, что этого не произойдет, ОДНА из переменных в c также должна быть uint64, и тогда она не будет переполняться. Вот почему int64 d работает, потому что он также был назначен.
Ответ №4:
Ваше предположение верно. Поскольку a и b являются значениями UINT, операция выполняется как UINT, и во время a * b * 4, что равно 2 ^ 32, она переполняется в 32-битном UINT как 0. Результат только затем преобразуется в UINT64.