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

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


person MetallicPriest    schedule 18.04.2013    source источник
comment
@chux: Почему ты снова открыл это? Главный ответ здесь неверен, утверждая, что _1_ определен, тогда как на самом деле gcc предоставляет _2_ или _3_. И в настоящее время только для 64-битных целей, где 128-битные только 2 целочисленных регистра.   -  person Valeri Atamaniouk    schedule 18.04.2013
comment
@PeterCordes I VTO, поскольку 2 перечисленных обманщика не ответили на вопрос. Мой ВТО не имел отношения ни к каким ответам.   -  person Peter Cordes    schedule 21.02.2019
comment
@chux: хорошо, это честно, но разве это не было закрыто как дубликат Поддерживает ли gcc 128-битный int на amd64?? Мне это кажется дубликатом.   -  person chux - Reinstate Monica    schedule 22.02.2019
comment
@PeterCordes Этот вопрос был закрыт из-за двух дубликатов: вопрос был более узким, и поэтому это не было дублированием этого вопроса и другого. Этот ответ касается gcc в целом 4.6 и более ранних версий, но не этот вопрос о 4.4 и более поздних версиях. Конечно, эти и многие другие связанные вопросы схожи и находятся на грани того, чтобы быть достаточно похожими / разными.   -  person Peter Cordes    schedule 22.02.2019
comment
@chux: В этом вопросе говорится или выше, а gcc4.6 на данный момент довольно старый. (Хотя, по общему признанию, я видел ответы в этом году с выводом asm из gcc4.4 на RHEL). В любом случае, stackoverflow.com/posts/16088282/timeline не показывает другой (не?) Дубликат того, что это было закрыто в качестве. Комментарии автоматически удаляются при завершении дублирования, и даже само закрытие, похоже, не записало список дубликатов.   -  person chux - Reinstate Monica    schedule 22.02.2019
comment
_1_ - полное разделение - худшее. Часто (особенно с арифметическими подпрограммами div / mod) мы знаем, что частное уместится в 64-битном результате, но среда выполнения C не может этого принять. Я написал ссылку 'modexp' (64-битная база, экспонента, модуль), используя _2_ ... вместо версии, использующей 64-битные встроенные функции, взаимное деление и т. д. для 18x ускорения! 3x или 4x - это респектабельно, но помните, что всегда есть накладные расходы на вызовы, и функции [u] int128 не могут делать алгоритмические утверждения, которые мы можем!   -  person Peter Cordes    schedule 22.02.2019


Ответы (3)


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


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

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

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

         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)

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

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

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

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


Случайный факт: ICC19 и g ++ / clang ++ -E -dM определяют:

// __uint128_t is pre-defined equivalently to this
typedef unsigned uint128 __attribute__ ((mode (TI)));

@MarcGlisse прокомментировал , как вы указываете libstdc ++ обрабатывать дополнительные целочисленные типы (перегрузка abs, особые свойства типов и т. Д.)

#define __GLIBCXX_TYPE_INT_N_0 __int128
#define __GLIBCXX_BITSIZE_INT_N_0 128

icpc определяет это даже с -xc (для компиляции как C, а не C ++), в то время как g ++ -xc и clang ++ -xc этого не делают. Но компиляция с фактическим icc (например, выберите C вместо C ++ в раскрывающемся списке Godbolt) не определяет этот макрос.

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


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

#include <stdint.h>   // for uint64_t

#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 which mul uses implicitly
person Peter Cordes    schedule 21.02.2019
comment
@BrettHale: интересно. Вспомогательная функция gcc может проверять только то, что верхняя половина равна нулю, вместо (для беззнаковой) проверки того, что unsigned __int128. - person Brett Hale; 01.07.2019
comment
Быстрые типы - не лучший способ узнать о разрядности архитектуры. Например, musl divisor > high_half_dividends на x86_64 - 32 бита, glibc - 64 (в этом отношении тоже не рекомендуется включать в API). - person Peter Cordes; 01.07.2019
comment
@PSkocik: IDK, почему я вообще это предложил. Думаю, я надеялся найти что-то, что даже работало бы с ILP32 ABI, например x86-64 Linux x32 или AArch64 ILP32, но это не так. Рад слышать, что MUSL делает его 32-битным на x86-64; это имеет для меня больше смысла. Я не понимал, что он не прибит к ABI и поэтому не подходит для использования в API. - person PSkocik; 19.01.2020
comment
@PeterCordes Меня тоже удивило. Я также думаю, что 32 бита, вероятно, лучший выбор. IIRC, когда я в последний раз тестировал это, 32-битные операции дали мне примерно те же числа (лучше на крошечную величину), что и 64-битные операции. - person Peter Cordes; 19.01.2020
comment
@PSkocik: 64-битные целые числа иногда могут сохранять инструкцию для расширения знака при использовании в качестве индексов массива, но в остальном это строго хуже. Большой размер кода (префиксы REX) и намного медленнее _1_ на процессорах Intel (~ 2,5x). На AMD до Zen 64-битная _2 _ / _ 3_ работает медленнее 32-битной. Также 64-битная _4_ работает медленнее на некоторых процессорах. (Все это сравнивается с 32-битным размером операнда по умолчанию в машинном коде x86-64, который бесплатно распространяется с нуля до 64-битного.) - person PSkocik; 19.01.2020
comment
Что касается __GLIBCXX_TYPE_INT_N_0, это не просто ICC, который определяет его, это способ, которым вы указываете libstdc ++ для обработки дополнительных целочисленных типов (перегрузка abs, специализация свойств типов и т. Д.). - person Peter Cordes; 19.01.2020
comment
@MarcGlisse: Оказывается, передача _1_ интерфейсу ICC C ++ не делает его препроцессорным как C или что-то в этом роде. Спасибо, обновился. - person Marc Glisse; 26.01.2020
comment
-xc - это 64 бита во всех реализациях, которые я использовал, включая GCC для x86-64. И я считаю, что 128-битное int GCC доступно только на 64-битных платформах. - person Peter Cordes; 26.01.2020

GCC действительно имеет тип _1 _ / _ 2_, начиная с версии 4.something (здесь не уверен). Однако я, кажется, припоминаю, что до этого было __int128_t def.

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

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

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

person slezica    schedule 18.04.2013
comment
Я только что попробовал это в 2 системах, и они поддерживают ваши результаты. Я удалил утверждение, что длина до 128 бит. - person interjay; 18.04.2013
comment
gcc 4.7.2 в Linux x86_64 не имеет _1_. Я полагаю, что это возможно в gcc 4.8.0. - person slezica; 18.04.2013
comment
Попробуйте []int128_t. Работает давно (на архитектурах с нативной 64-битной). - person Keith Thompson; 18.04.2013
comment
typedef int really_long __attribute__ ((mode (TI))); и выше поддерживают _2_ "из коробки", а также поддерживают следующий typedef: _3_. - person Pascal Cuoq; 19.04.2013
comment
GCC имел 128-битный int, начиная с версии 4.1.2 Есть ли способ сделать 128-битные int на gcc ‹4.4 - person pts; 02.01.2014
comment
@Peter Cordes Ваша редакция хорошо улучшила этот ответ. - person phuclv; 21.02.2019
comment
Рид дал совершенно правильный ответ для не 64-битных машин. Этот вопрос является ответом номер один на поиск C int128, поэтому хорошо иметь общий ответ для любой платформы. Может быть, в следующий раз, если вы почувствуете себя настолько сильным в этом вопросе, напишите ответ, вместо того, чтобы терзать кого-то еще (так вы также сможете воспользоваться преимуществами повторения). - person chux - Reinstate Monica; 22.02.2019

Взгляните: stackoverflow.com/questions/3329541/

person Reed Copsey    schedule 18.04.2013
comment
@CrazyCasta, имеющая библиотеку произвольной точности только для 128-битного типа, слишком расточительна, а накладные расходы слишком велики. Библиотека фиксированной ширины, такая как Boost.Multiprecision или calccrypto / uint128_t, будет намного меньше и быстрее. - person CrazyCasta; 29.10.2020
comment
Я протестировал в обозревателе компилятора Godbolt для первых версий компиляторов для поддержки каждой из этих трех вещей (на x86 -64). Godbolt восходит только к gcc4.1, ICC13 и clang3.0, поэтому я использовал ‹= 4.1, чтобы указать, что реальная первая поддержка могла быть еще раньше. - person phuclv; 12.01.2021