gcc中有128位整数吗?
Posted
技术标签:
【中文标题】gcc中有128位整数吗?【英文标题】:Is there a 128 bit integer in gcc? 【发布时间】:2013-04-11 21:10:46 【问题描述】:我想要一个 128 位整数,因为我想存储两个 64 位数字相乘的结果。 gcc 4.4 及更高版本中有这样的东西吗?
【问题讨论】:
看一看:***.com/questions/3329541/… @chux:你为什么重新打开这个?这里的最佳答案是错误的,声称uint128_t
是在实际上gcc 提供unsigned __int128
或__uint128_t
时定义的。目前仅适用于 64 位目标,其中 128 位仅需要 2 个整数寄存器。
@PeterCordes I VTO 作为列出的 2 个受骗者没有回答问题。我的 VTO 与任何答案无关。
@chux: 好吧,这很公平,但它不是作为Does gcc support 128-bit int on amd64? 的副本而关闭的吗?对我来说,这看起来像是重复的。
@PeterCordes 这个问题由于 2 个骗子而被关闭:question 更窄,所以不是这个问题的骗子——还有另一个。 answer 一般在 4.6 及之前解决 gcc,但不是这个问题是关于 4.4 以后的。当然,这些和许多其他相关问题是相似的,并且处于足够相似/不同的边界
【参考方案1】:
您可以使用处理任意或较大精度值的库,例如 GNU MP Bignum Library。
【讨论】:
Reed 对非 64 位机器给出了完全有效的答案。这个问题是对“C int128”搜索的第一反应,因此对任何平台都有一个通用的答案是一件好事。也许下次如果您对这个主题感到如此强烈,请写一个答案而不是撕毁别人(这样您也可以获得代表收益)。 @CrazyCasta 拥有一个仅用于 128 位类型的任意精度库太浪费了,而且开销也太大了。像Boost.Multiprecision or calccrypto/uint128_t 这样的固定宽度库会更小更快【参考方案2】:啊,大整数不是 C 的强项。
GCC 确实有一个 unsigned __int128
/__int128
类型,从版本 4.something 开始(这里不确定)。不过,我似乎确实记得在那之前有一个__int128_t
def。
这些仅适用于 64 位目标。
(编者注:这个答案曾经声称 gcc 定义了 uint128_t
和 int128_t
。我在 Godbolt 编译器资源管理器上测试的所有版本都没有定义那些没有前导 __
的类型,从 gcc4.1 到 8.2 ,或clang或ICC。)
【讨论】:
long long int
在我使用的每个实现中都是 64 位,包括 x86-64 的 GCC。而且我相信 GCC 的 128 位 int 只能在 64 位平台上使用。
我刚刚在 2 个系统中尝试过,它们支持您的结果。我已经删除了它长达 128 位的断言。
Linux x86_64 上的 gcc 4.7.2 没有 []int128_t
。我想 gcc 4.8.0 可能有它。
试试typedef int really_long __attribute__ ((mode (TI)));
。它已经工作了很长时间(在原生 64 位架构上)。
gcc-4.1 -m64
及以上版本支持__uint128_t
out-of-the-box,还支持以下typedef:typedef unsigned uint128_t __attribute__ ((mode (TI)));
。【参考方案3】:
128 位整数类型仅在 64 位目标上可用,因此即使您已经检测到最近的 GCC 版本,您也需要检查可用性。理论上 gcc 可以在需要 4 个 32 位寄存器来保存一个的机器上支持 TImode 整数,但我认为在任何情况下都不会。
GCC 4.6 及更高版本将__int128
/ unsigned __int128
定义为内置类型。 使用#ifdef __SIZEOF_INT128__
来检测它。
GCC 4.1 及更高版本将__int128_t
和__uint128_t
定义为内置类型。 (这些也不需要#include <stdint.h>
。证明on Godbolt。)
我测试了on the Godbolt compiler explorer 的第一个版本的编译器来支持这三样东西(在 x86-64 上)。 Godbolt 只回溯到 gcc4.1、ICC13 和 clang3.0,所以我使用
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)
如果您为 ARM 等 32 位架构或带有 -m32
的 x86 进行编译,即使是这些编译器的最新版本也不支持 128 位整数类型。 需要在使用之前检测支持,如果您的代码在没有它的情况下可以正常工作。
我知道用于检测它的唯一直接 CPP 宏是 __SIZEOF_INT128__
,但不幸的是,一些旧的编译器版本支持它而没有定义它。 (并且__uint128_t
没有宏,只有 gcc4.6 样式 unsigned __int128
)。 How to know if __uint128_t is defined
有些人仍然在 RHEL (RedHat Enterprise Linux) 或类似的老旧系统上使用 gcc4.4 等古老的编译器版本。如果你关心过时的 gcc 版本,你可能想坚持__uint128_t
。并且可能根据sizeof(void*) == 8
检测64 位作为__SIZEOF_INT128__
未定义的后备。 (我认为 GNU 系统总是有CHAR_BIT==8
)。这将对 64 位 ISA(如 x86-64 Linux x32 或 AArch64 ILP32)上的 ILP32 ABI 产生误报,但这对于使用未定义 __SIZEOF_INT128__
的旧编译器的人来说已经只是一个后备/奖励。
可能有一些 64 位 ISA,其中 gcc 没有定义 __int128
,或者甚至可能有一些 32 位 ISA,其中 gcc 确实 定义了 __int128
,但我不知道任何一个。
正如此处另一个答案中的 cmets 所指出的,GCC 内部是整数 TI 模式。 (四整数 = int
的 4 倍宽度,DImode = 双宽度 vs. SImode = 普通 int
。)与 the GCC manual points out 一样,__int128
在支持 128 位整数模式的目标上受支持(TImode )。
// __uint128_t is pre-defined equivalently to this
typedef unsigned uint128 __attribute__ ((mode (TI)));
随机事实:ICC19 和 g++/clang++ -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 位内在函数的版本、reciprocal division 等相比,18x i> 加速! 3x 或 4x 是可观的,但请记住,总有调用开销,并且 [u]int128 函数无法做出我们可以做出的算法断言!
@BrettHale:很有趣。 gcc 的辅助函数可能只检查上半部分是否为零,而不是(对于无符号)检查 divisor > high_half_dividend
。
快速类型并不是了解架构位数的好方法。例如,musl 在 x86_64 上的 ,uint_fast16,32_t
s 是 32 位的,glibc 是 64 位(也不好包含在 API 中)。
@PSkocik:不知道为什么我什至首先建议这样做。我想我一直希望找到甚至可以在 ILP32 ABI 上工作的东西,比如 x86-64 Linux 的 x32 或 AArch64 ILP32,但事实并非如此。很高兴听到 MUSL 在 x86-64 上使其成为 32 位;这对我来说更有意义。我没有意识到它没有被 ABI 确定,因此不适合在 API 中使用。
@PSkocik:64 位整数在用作数组索引时有时可以保存符号扩展指令,但在其他方面则更糟。较大的代码大小(REX 前缀),在 Intel CPU (~2.5x) 上更慢 div
。在 Zen 之前的 AMD 上,64 位 mul
/imul
比 32 位慢。此外,64 位 popcnt
在某些 CPU 上速度较慢。 (所有这些都与 32 位相比,它是 x86-64 机器代码中的默认操作数大小,它免费零扩展为 64 位。)以上是关于gcc中有128位整数吗?的主要内容,如果未能解决你的问题,请参考以下文章
Cortex-A57 可以双发 128 位 neon 指令吗?