我需要一个128位整数,因为我要存储两个64位数相乘的结果。在gcc 4.4及以上版本中有这样的东西吗?
boost::multiprecision::int128_t
这样的库,如果可用,它将使用编译器内置的宽类型,与使用自己的 typedef(例如 GCC 的 __int128
或 Clang 的 _BitInt(128)
)相比,具有零开销。另请参见@phuclv's answer中的另一个问题。typedef unsigned _BitInt(128) u128
,这是基于 clang的功能建模的,最初称为_ExtInt()
,即使在32位机器上也可以工作;请参见 简短介绍。当前的GCC -std=gnu2x
甚至还不支持该语法。
__int128
/unsigned __int128
作为内置类型。使用#ifdef __SIZEOF_INT128__
来检测它。
GCC 4.1及更高版本将__int128_t
和__uint128_t
定义为内置类型。(这些类型不需要#include <stdint.h>
,可以在Godbolt上证明。)
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)
-m32
的x86架构,即使是最新版本的这些编译器也不支持128位整数类型。因此,如果你的代码没有这个类型的支持,就需要在使用之前进行检测,以确保代码可以正常工作。
我所知道的唯一直接检测宏是__SIZEOF_INT128__
,但不幸的是,一些旧版本的编译器支持它却没有定义它。(而且没有__uint128_t
的宏,只有gcc4.6风格的unsigned __int128
)。如何确定是否已定义__uint128_t
__uint128_t
。也许可以通过检测sizeof(void*) == 8
来确定64位性,作为__SIZEOF_INT128__
未定义的后备方案。 (我认为GNU系统始终具有CHAR_BIT==8
,尽管我可能对某些DSP存在误解)。 这将在64位ISA上的ILP32 ABI上产生错误的负面影响(例如x86-64 Linux x32或AArch64 ILP32),但这已经是针对不定义__SIZEOF_INT128__
的旧编译器用户的后备/奖励了。__int128
,甚至可能有一些32位ISA gcc定义了__int128
,但我不知道。
int
的4倍宽度,双模式=DImode=双倍宽度,普通int
=SImode。)正如GCC手册所指出的,在支持128位整数模式(TImode)的目标上支持__int128
。// __uint128_t is pre-defined equivalently to this
typedef unsigned uint128 __attribute__ ((mode (TI)));
-E -dM
定义:#define __GLIBCXX_TYPE_INT_N_0 __int128
#define __GLIBCXX_BITSIZE_INT_N_0 128
@MarcGlisse发表评论,指出这是告诉libstdc++如何处理额外的整数类型(重载abs、特化类型特征等)的方法。
icpc
定义了即使使用-xc
(编译为C而不是C ++),而g ++ -xc和clang ++ -xc则不定义。但是使用实际的icc
进行编译(例如,在Godbolt语言下拉菜单中选择C而不是C ++)不会定义此宏。
测试函数为:
#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
unsigned __int128
- 全除法是最慢的。经常情况下(特别是在div / mod算术例程中),我们知道商将适合于64位结果,但C运行时不能假设它。 我编写了一个基于__int128
的参考“modexp”(64位基数,指数,模数)......相对于使用64位intrinsic,倒数除法等版本,加速了18倍! 3倍或4倍是可观的,但请记住总是有调用开销,并且[u]int128函数无法像我们一样进行算法断言! - Brett Halediv
(约为2.5倍)。在Zen之前的AMD上,64位mul
/imul
比32位慢。此外,某些CPU上64位popcnt
也较慢。(所有这些都与32位进行比较,即x86-64机器代码中的默认操作数大小,它免费进行零扩展到64位。) - Peter Cordes啊,大整数并不是 C 语言的长项。
GCC 版本从 4.x 开始引入了 unsigned __int128
/__int128
类型(不太确定),但我似乎记得在此之前有一个 __int128_t
的定义。
这些类型仅适用于 64 位目标平台。
(编者注:该回答曾声称 GCC 定义了 uint128_t
和 int128_t
这两种类型,但我在 Godbolt 编译器浏览器上测试过的所有版本中都没有对这些类型进行定义,从 gcc4.1 到 8.2,以及 clang 和 ICC。)
[]int128_t
。我猜测gcc 4.8.0可能会有它。 - Keith Thompsontypedef int really_long __attribute__ ((mode (TI)));
。在具有本地64位支持的架构上已经运作了很长一段时间。 - Pascal Cuoq__uint128_t
类型,并且还支持以下typedef:typedef unsigned uint128_t __attribute__ ((mode(TI)));
。 - pts你可以使用处理任意或大精度值的库,例如GNU MP 大整数库。
uint128_t
已定义,而事实上gcc提供了unsigned __int128
或__uint128_t
。目前只在64位目标上提供128位,只需要2个整数寄存器。 - Peter Cordes