Есть ли 128-битное целое число в gcc?

Я хочу 128-битное целое число, потому что хочу сохранить результаты умножения двух 64-битных чисел. Есть ли такая вещь в gcc 4.4 и выше?

Ответы

Ответ 1

128-разрядный целочисленный тип доступен только для 64-разрядных целей, поэтому вам необходимо проверить доступность, даже если вы уже обнаружили последнюю версию GCC. Теоретически gcc может поддерживать целые числа TImode на машинах, где для его хранения потребуется 4 32-битных регистра, но я не думаю, что бывают случаи, когда это происходит.


GCC 4.6 и более поздние __int128 имеют __int128/unsigned __int128 определенный как встроенный тип. использование
#ifdef __SIZEOF_INT128__ чтобы обнаружить его.

GCC 4.1 и более поздние __int128_t определяют __int128_t и __uint128_t в <stdint.h>. В последних компиляторах это, по-видимому, определяется в терминах __int128. (Вам все еще нужно #include <stdint.h> если вы хотите использовать имя __int128_t вместо __int128.)

Я проверил #define uint128_t __uint128_t //#define uint128_t unsigned __int128 uint128_t mul64(uint64_t a, uint64_t+b) {%0a+ return (uint128_t)a+*+b; } #ifdef __SIZEOF_INT128__ int detected_ok(){return 1;} #endif '),l:'5',n:'0',o:'C++ source #1',t:'0')),k:33.32694763729248,l:'4',m:100,n:'0',o:'',s:0,t:'0'),(g:!((g:!((h:compiler,i:(compiler:g412,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'1',trim:'1'),fontScale:1.2899450879999999,lang:c++,libs:!((name:boost,ver:'167')),options:'-xc -O3',source:1),l:'5',n:'0',o:'x86-64 gcc 4.1.2+(Editor #1,+Compiler+#1)+C++',t:'0')),header:(),k:33.3397190293742,l:'4',m:56.14564870956661,n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:icc1301,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'1',trim:'1'),fontScale:1.2899450879999999,lang:c++,libs:!((name:boost,ver:'167')),options:'-xc -O3 -xHOST',source:1),l:'5',n:'0',o:'x86-64 icc 13.0.1+(Editor #1,+Compiler+#2)+C++',t:'0')),header:(),l:'4',m:43.8543512904334,n:'0',o:'',s:0,t:'0')),k:33.3397190293742,l:'3',n:'0',o:'',t:'0'),(g:!((h:compiler,i:(compiler:clang30,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'1',trim:'1'),fontScale:1.2899450879999999,lang:c++,libs:!((name:boost,ver:'167')),options:'-xc -O3',source:1),l:'5',n:'0',o:'x86-64+Clang 3.0.0+(Editor #1,+Compiler+#3)+C++',t:'0')),k:33.33333333333333,l:'4',m:100,n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4 rel="nofollow noreferrer">на проводнике компилятора Godbolt первые версии компиляторов для поддержки каждой из этих трех вещей (на x86-64). Godbolt восходит только к gcc4.1, ICC13 и clang3.0, поэтому я использовал <= 4.1, чтобы указать, что фактическая первая поддержка могла быть еще раньше.

         legacy               recommended(?)    |  One way of detecting support
        __uint128_t   |  [unsigned]  __int128   |  #ifdef __SIZEOF_INT128__
gcc        <=  4.1    |       4.6               |     4.6
clang      <=  3.0    |       3.1               |     3.3
ICC        <=  13     |     <= 13               |     16.  (Godbolt doesn't have 14 or 15)

Если вы компилируете для 32-битной архитектуры, такой как ARM или x86, с -m32, то 128-битный целочисленный тип не поддерживается даже в самой новой версии любого из этих компиляторов. Поэтому вам необходимо определить поддержку перед использованием, если ваш код вообще может работать без нее.

Единственный прямой CPP-макрос, о котором я знаю, для его обнаружения - это __SIZEOF_INT128__, но, к сожалению, некоторые старые версии компилятора поддерживают его, не определяя его. (И нет макроса для __uint128_t, только стиль unsigned __int128). Как узнать, определен ли __uint128_t

Некоторые люди до сих пор используют древние версии компиляторов, такие как gcc4.4 в RHEL (RedHat Enterprise Linux), или подобные старые системы. Если вам нужны такие устаревшие версии gcc, вы, вероятно, захотите придерживаться __uint128_t. И, возможно, определить 64-битность с точки зрения sizeof(int_fast32_t) который по некоторым причинам равен 8 на некоторых 64-битных ISA. Но не на ILP32 ISA, таких как x32 или ILP32 AArch64, поэтому, возможно, просто проверьте sizeof(void*) если __SIZEOF_INT128__ не определен.

Могут быть некоторые 64-битные ISA, где gcc не определяет __int128, или, может быть, даже некоторые 32-битные ISA, где gcc действительно определяет __int128, но я не знаю ни одного.

Как отмечают комментарии к другому ответу, внутренняя часть GCC является целочисленным режимом TI. (Tetra-integer = 4x width of int, против DImode = double width против SImode = plain int.) Как указывает руководство GCC, __int128 поддерживается для целей, которые поддерживают 128-битный целочисленный режим (TImode).

typedef unsigned uint128_t __attribute__ ((mode (TI)));

Случайный факт: ICC19 -E -dM определяет:

#define __GLIBCXX_TYPE_INT_N_0 __int128
#define __GLIBCXX_BITSIZE_INT_N_0 128

Тестовая функция была:

#include <stdint.h>

#define uint128_t __uint128_t
//#define uint128_t unsigned __int128

uint128_t mul64(uint64_t a, uint64_t b) {
    return (uint128_t)a * b;
}

компиляторы, которые поддерживают все это, эффективно компилируют

    mov       rax, rdi
    mul       rsi
    ret                          # return in RDX:RAX

Ответ 2

Ах, большие целые числа не являются сильными сторонами.

GCC имеет unsigned __int128/__int128, начиная с версии 4. что-то (здесь не уверен). Тем не менее, я напоминаю, что до этого была __int128_t.

Они доступны только для 64-битных целей.

(Примечание редактора: этот ответ использовался для утверждения, что gcc определил uint128_t и int128_t. Ни одна из версий, которые я тестировал в проводнике компилятора Godbolt, не определяет эти типы без лидирующих __, от gcc4.1 до 8.2, или clang или ICC.)

Ответ 3

Вы можете использовать библиотеку, которая обрабатывает произвольные или большие значения точности, такие как библиотека GNU MP Bignum.