Я пытаюсь запустить приведенную ниже программу на 32-битной платформе Linux.
int main()
{
unsigned long long val = 0;
val = 140417 * 100000 + 92 + 1;
}
Выходное значение является некоторым значением мусора (1156798205).
После некоторых исследований я обнаружил, что:Вот
long long size: 64 bits (MAX VALUE: signed long long = 144115188075855871, unsigned long long = 1073741823)
Приведенный выше код создает одну и ту же проблему с Visual Studio 2005 для обоих типов данных: unsigned long long и подписано long long.
Но согласно документации MSDN:
Вот
unsigned long long 8 byte range of values 0 to 18,446,744,073,709,551,615
Мне интересно, как обрабатывать большой диапазон значений в 32-битной платформе Linux с помощью программы C ++.
Спасибо за помощь.
Проблема в том, что, хотя вы используете 64-битный тип данных, в ваших вычислениях используются 32-битные значения, поэтому вы столкнулись с целочисленным переполнением. 140417 * 100000
14041700000 (0x344F356A0) в 64-битной версии, но 1156798112 (0x44F356A0) в 32-битной. Как вы можете видеть, 0x300000000 усекается из результата, так как он не вписывается в 32-битное значение.
Вы должны убедиться, что вы используете 64-битные вычисления, например:
typedef unsigned long long ulong64_t;
int main()
{
ulong64_t val = 0;
val = ulong64_t(140417) * ulong64_t(100000) + 92 + 1;
}
В качестве альтернативы используйте суффиксы целочисленной константы:
int main()
{
unsigned long long val = 0;
val = 140417i64 * 100000i64 + 92 + 1;
}
Или же:
int main()
{
unsigned long long val = 0;
val = 140417ull * 100000ull + 92 + 1;
}
Проблема в том, что тип целой константы без суффикса (например, 42
) самый маленький из int
, long int
, long long int
это может содержать его значение, и тип выражения определяется самим выражением, а не контекстом, в котором оно появляется.
Так что если int
бывает 32 бит в вашей системе, то в этом:
unsigned long long val = 140417 * 100000 + 92 + 1;
константы 140417
а также 100000
(которые вмещаются в 32 бит) имеют тип int
и умножение — это 32-битное умножение, которое переполняется, потому что произведение этих двух чисел не умещается в 32 бита. (Тип отдельного литерала корректируется в зависимости от его значения; тип большего выражения — нет.)
Самый простой способ избежать этого — использовать константы типа unsigned long long
:
unsigned long long val = 140417ULL * 100000ULL + 92ULL + 1ULL;
(Бывает, что не все ULL
суффиксы необходимы, но не мешает применять их ко всем константам в выражении.)
Если вы распечатываете: sizeof(unsigned long long)
максимум 2 ^ (это значение) -1.
Мне интересно, как обрабатывать большой диапазон значений в 32-битной платформе Linux с помощью программы C ++.
добавлять #include <stdint.h>
и использовать явный long long
или предпочтительно int64_t
или же uint64_t
типы.
Недавний GCC (например, GCC 4.9, выпущенный в середине апреля 2014 года) может иметь __int128
,
Если вы хотите обрабатывать очень большие числа (больше 263 в абсолютном значении), так называемый bignums вам понадобится библиотека Bignum (например, GMPlib), или язык, поддерживающий их изначально (например, Common Lisp, используя SBCL ….)
Кстати, следующая программа
#include <stdio.h>
int main () {
unsigned long long val = 0;
val = 140417 * 100000LL + 92 + 1;
printf ("val=%lld\n", val);
return 0;
}
работает на Linux x86 32 бит. Если вы опустите LL
суффикс для 100000
(суффикс LL
нужно было получить long long
константа литерала 100000) вы получите предупреждение integer overflow in expression
в компилировать время с gcc -Wall hpfe.c -o hpfe
….