Целочисленное переполнение в логических выражениях

У меня есть следующий код C ++:

#include <iostream>

using namespace std;

int main()
{
long long int currentDt = 467510400*1000000;
long long int addedDt = 467510400*1000000;
if(currentDt-addedDt >= 0 && currentDt-addedDt <= 30*24*3600*1000000)
{
cout << "1" << endl;
cout << currentDt-addedDt << endl;

}
if(currentDt-addedDt > 30*24*3600*1000000 && currentDt-addedDt <= 60*24*3600*1000000)
{
cout << "2" << endl;
cout << currentDt-addedDt << endl;

}
if(currentDt-addedDt > 60*24*3600*1000000 && currentDt-addedDt <= 90*24*3600*1000000)
{
cout << "3" << endl;
cout << currentDt-addedDt << endl;

}

return 0;
}

Во-первых, я получаю предупреждение о целочисленном переполнении, которое мне кажется странным, потому что число 467510400 * 1000000 вполне укладывается в диапазон длинных длинных чисел, не так ли? Во-вторых, я получаю следующий вывод:

1
0
3
0

Если в обоих случаях значение currentDt-AddedDt равно 0, как может третий оператор if вычислить значение true?

2

Решение

467510400*1000000 находится в пределах диапазона long long, но это не в пределах диапазона int, Поскольку оба литерала имеют тип intтип продукта также имеет тип int — и это переполнится. Просто потому, что вы присваиваете результат long long не меняет значение, которое присваивается. По той же причине, что и в:

double d = 1 / 2;

d будет держать 0.0 и не 0.5,

Вам нужно явно привести один из литералов к большему целому типу. Например:

long long int addedDt = 467510400LL * 1000000;
5

Другие решения

   long long int currentDt = 467510400ll*1000000ll;
long long int addedDt = 467510400ll*1000000ll;

Обратите внимание на две строчные буквы «l» после цифр. Это делает ваши константы длинными. C ++ обычно интерпретирует строки цифр в источнике как простые ints.

0

Проблема в том, что все ваши целочисленные литералы int, Когда вы умножаете их, они переполняются, давая вам неожиданное поведение. Чтобы исправить это, вы можете сделать их long long использование литералов 467510400ll * 1000000ll

0

Это потому что

60*24*3600*1000000 evaluates to -25526272

использование

60LL*24LL*3600LL*1000000LL

вместо этого (обратите внимание на суффикс ‘LL’)

0

Вы отметили это с C ++.

Мое минимальное изменение в вашем коде будет использовать c ++ static_cast для преобразования по крайней мере одного из литеральных чисел (любого выражения, генерирующего переполнение) в int64_t (находится в файле включения cstdint).

Пример:

//          0         true
if(currentDt-addedDt  >= 0

&&   // true because vvvv

//          0        true
currentDt-addedDt <= 30*24*3600*static_cast<int64_t>(1000000))
//                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

(для теста 1 результат предложения if равен true.
для теста 2 и 3 ложно)

Найдя static_cast, компилятор переводит 3 других целых числа (в разделе) в int64_t и, таким образом, не генерирует предупреждений о переполнении.

Да, это добавляет много символов для того, чтобы быть, в некотором смысле, «минимальным».

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector