Несогласованные результаты при вычислении одного и того же целого числа с разными выражениями - PullRequest
0 голосов
/ 13 апреля 2019

Арифметический результат для одного и того же выражения приводит к разным результатам в зависимости от того, задаю ли я целое число в одной строке или использую несколько шагов:

int main() {

    unsigned long long veryBigIntOneLine = ((255*256+255)*256+255)*256+255;

    unsigned long long veryBigInt = 255;
    veryBigInt *= 256;
    veryBigInt += 255;
    veryBigInt *= 256;
    veryBigInt += 255;
    veryBigInt *= 256;
    veryBigInt += 255;

    unsigned long long veryBigIntParanthesis = (((((255*256)+255)*256)+255)*256)+255;

    unsigned long long fourthInt = 256;
    fourthInt *= 256;
    fourthInt *= 256;
    fourthInt *= 256;
    --fourthInt;

    cout << "veryBigIntOneLine: " << veryBigIntOneLine << endl;
    cout << "veryBigInt: " << veryBigInt << endl;
    cout << "veryBigIntParanthesis: " << veryBigIntParanthesis << endl;
    cout << "fourthInt: " << fourthInt << endl;

    return 0;

}

все они должны описывать одно и то же число, 256^ 4-1 (или 2 ^ 32-1 ), но результат будет другим.

veryBigIntOneLine: 18446744073709551615
veryBigInt: 4294967295
veryBigIntParanthesis: 18446744073709551615
fourthInt: 4294967295

4294967295 - ожидаемый ответ (какон дается для всех четырех выражений калькулятором Google).

Также 18446744073709551615 , вероятно, не является точным результатом того, что вычисляется, поскольку я получаю предупреждение о переполнении во время компиляции для обеих строквыражения (даже когда я пытался с типом __int128).На самом деле это 2 ^ 64-1 , что является максимальным значением для длинных без знака с моим компилятором ( veryBigIntOneLine + 1 дает 0 ).

Ответы [ 2 ]

2 голосов
/ 13 апреля 2019

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

Простое использование соответствующих литералов устранит эти проблемы:

unsigned long long veryBigIntOneLine{ ((255ull*256ull+255ull)*256ull+255ull)*256ull+255ull}; // 4294967295
0 голосов
/ 13 апреля 2019

Это потому, что вы не используете unsigned long long литералы.Если вы хотите, чтобы литералы соответствовали вашим определениям, вам нужно использовать:

255ULL + 256ULL * 255ULL + ...

ULL очень важно, если вы создаете 64-битные числа.В Си без суффикса число может быть 64, 32 или даже 16 битами (даже байтами в некотором CRAY, где 64 бита. Это также означает, что ваш код сработал бы просто найти в одной из этих систем CRAY.)

...