Ошибка, которая, кажется, вызвана целочисленным переполнением для конкретного случая - PullRequest
0 голосов
/ 06 мая 2019

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

Часть программы, которую я пишу, суммирует некоторые большие числа.Вот код, который у меня сейчас есть:

Ball* tmp = player2->RemoveMaxNode();
if (!tmp->GetChosen())
{
    cout << player2->GetHeapType() << " is chosing " << tmp->GetValue() <<  "-" << tmp->GetSumOfDigits() <<endl;
    cout << "Adding " << tmp->GetValue() << " to ";
    cout << player2->GetScore();
    cout << " which should = " << tmp->GetValue() + player2->GetScore() << endl;
    player2->UpdateScore(tmp->GetValue());
    cout << player2->GetHeapType()<< " score now is: ";
    cout << player2->GetScore();
    cout << endl;
    tmp->SetChosen(true);
    numberOfBalls--;
    j++;
    // cout << endl;
}

С моей функцией UpdateScore ():

void Heap::UpdateScore(unsigned long int value)
{
    this->currentScore += value;
}

Это даст мне вывод:

AGENT1 is chosing 937504347-42
Adding 937504347 to 0 which should = 937504347
AGENT1 score now is: 937504347
AGENT1 is chosing 709551656-44
Adding 709551656 to 937504347 which should = 1647056003
AGENT1 score now is: 1647056003
AGENT1 is chosing 681463104-33
Adding 681463104 to 1647056003 which should = 2328519107
AGENT1  score now is: 2328519107
AGENT1 is chosing 672306410-29
Adding 672306410 to 2328519107 which should = 3000825517
AGENT1 score now is: 3000825517
AGENT1 is chosing 667082001-30
Adding 667082001 to 3000825517 which should = 3667907518
AGENT1 score now is: 3667907518
AGENT1 is chosing 378250713-36
Adding 378250713 to 3667907518 which should = 4046158231
AGENT1 score now is: 4046158231
AGENT1 is chosing 309421734-33
Adding 309421734 to 4046158231 which should = 60612669
AGENT1 score now is: 60612669
AGENT1 is chosing 206733105-27
Adding 206733105 to 60612669 which should = 267345774
AGENT1 score now is: 267345774
AGENT1 is chosing 151431905-29
Adding 151431905 to 267345774 which should = 418777679
AGENT1 score now is: 418777679
AGENT1 is chosing 13048925-32
Adding 13048925 to 418777679 which should = 431826604
AGENT1 score now is: 431826604

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

AGENT1 is chosing 309421734-33
Adding 309421734 to 4046158231 which should = 60612669
AGENT1 score now is: 60612669

. Итоговое число от этого дополнения должно быть 4 355 579 965, но вместо этого оно равно 60612669. Разница в этих двух числах4 294 967 296, который, как я знаю, является максимальным размером 2 ^ 32-битного целого числа.Поэтому я изменил все свои переменные на unsigned long int.Значение tmp равно unsigned long int, равно как и значение player2.Однако проблема сохраняется, и я не знаю, что я могу сделать.Я думал, что это целочисленная ошибка переполнения, поэтому я жестко запрограммировал все целочисленные значения, которые нужно добавить друг к другу, и получил ошибку переполнения.

main.cpp: In function 'int main(int, char**)':
main.cpp:147:53: warning: integer overflow in expression [-Woverflow]
         unsigned long int asdf = 937504347+709551656+681463104+672306410+667082001+378250713+309421734+206733105+151431905+13048925;
                                  ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~

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

Спасибо.

1 Ответ

0 голосов
/ 06 мая 2019

Относительно оператора типа:

unsigned long int asdf = 937504347 + 709551656;

int значения 937504347 и 709551656 складываются вместе, создавая результат int, который затем загружается в unsigned long переменная.Чтобы избежать переполнения на этапе int -add, вы уже должны использовать правильный тип, такой как:

unsigned long int asdf = 937504347UL + 709551656UL;

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

Однако ваше утверждение, что вы увидите тот же результат для произвольных значений, которые компилятор не знает во время компиляции,неверен.Это просто добавит значения и значения без знака.Вероятно, он также будет переносить значения со знаком, но технически это неопределенное поведение, поэтому не удивляйтесь, если он отформатирует ваш жесткий диск: -)


В любом случае, стандарт гарантирует только то, что типыболее высокий ранг имеет больший или равный диапазон до меньших рангов.Для unsigned long требуется всего , требуется , чтобы быть 32 битами (точнее, иметь диапазон, который может быть представлен 32 битами).Если вы хотите гарантированный размер, используйте типы uintX_t, найденные в cstdint.Тип uint64_t должен значительно расширить ваш диапазон, давая вам гарантированное максимальное значение около восемнадцати квинтиллионов (18,446,744,073,709,551,615).

...