У меня есть следующий код 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?
467510400*1000000
находится в пределах диапазона long long
, но это не в пределах диапазона int
, Поскольку оба литерала имеют тип int
тип продукта также имеет тип int
— и это переполнится. Просто потому, что вы присваиваете результат long long
не меняет значение, которое присваивается. По той же причине, что и в:
double d = 1 / 2;
d
будет держать 0.0
и не 0.5
,
Вам нужно явно привести один из литералов к большему целому типу. Например:
long long int addedDt = 467510400LL * 1000000;
long long int currentDt = 467510400ll*1000000ll;
long long int addedDt = 467510400ll*1000000ll;
Обратите внимание на две строчные буквы «l» после цифр. Это делает ваши константы длинными. C ++ обычно интерпретирует строки цифр в источнике как простые int
s.
Проблема в том, что все ваши целочисленные литералы int
, Когда вы умножаете их, они переполняются, давая вам неожиданное поведение. Чтобы исправить это, вы можете сделать их long long
использование литералов 467510400ll * 1000000ll
Это потому что
60*24*3600*1000000 evaluates to -25526272
использование
60LL*24LL*3600LL*1000000LL
вместо этого (обратите внимание на суффикс ‘LL’)
Вы отметили это с 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 и, таким образом, не генерирует предупреждений о переполнении.
Да, это добавляет много символов для того, чтобы быть, в некотором смысле, «минимальным».