是否有 256 位整数类型?
Is there a 256-bit integer type?
OS: Linux (Debian 10)
CC:海湾合作委员会 8.3
CPU:i7-5775C
在 GCC 中有一个 unsigned __int128
/__int128
,但是有没有办法在 GCC 中有一个 uint256_t
/int256_t
?
我读到 __m256i
好像是英特尔的。是否有任何 header 我可以包含以获取它?
是否像假设的unsigned __int256
一样可用?我的意思是如果你可以给它赋值from/to,比较它们,按位运算等等
它的带符号等价物是多少(如果有)?
编辑 1:
我做到了:
#include <immintrin.h>
typedef __m256i uint256_t;
并编译。如果我可以用它做一些操作,我会在这里更新它。
编辑 2:
发现的问题:
uint256_t m;
int l = 5;
m = ~((uint256_t)1 << l);
输出:
error: can’t convert a value of type ‘int’ to vector type ‘__vector(4) long long int’ which has different size
m = ~((uint256_t)1 << l);
Clang 有 _ExtInt
extended integers 支持除法以外的操作,但 SIMD 对此没有用,因为元素之间有进位 1。其他主流 x86-64 编译器甚至都没有;您需要一个库或其他东西来定义自定义类型,并使用 clang 将使用的相同的 add-with-carry 指令。 (或者纯 C 中效率较低的仿真 2)。
__m256i
是 AVX2 SIMD 4x uint64_t
(或更窄的元素大小,如 8x uint32_t
)。 它不是 256 位标量整数类型,您不能将其用于标量运算,__m256i var = 1
甚至无法编译。 x86 SIMD 不支持宽度大于 64 位的整数,而像 __m128i
和 __m256i
这样的 Intel 内在类型纯粹是针对 SIMD 的。
GCC的__int128
/unsigned __int128
通常使用标量add/adc
,and/or标量mul
/imul
,因为AVX2一般没有帮助为了扩展精度。 (仅适用于元素边界无关紧要的按位 AND/OR/XOR。)
脚注 1:对于 BigInteger 类型,实际上有一定的使用 SIMD 的范围,但仅限于特殊格式。更重要的是,您必须手动选择何时重新归一化(传播进位),因此您的计算必须围绕它进行设计;它不是直接替代品。请参阅 Mysticial 在 Can long integer routines benefit from SSE?
上的回答
脚注 2:不幸的是,C 不提供加法/减法的进位运算,因此用 C 编写甚至不方便。sum = a+b
/ carry = sum<a
在没有进位的情况下用于执行,但是用 C 编写一个完整的加法器要困难得多。而且编译器通常会生成垃圾 asm,它不只是在可用的机器上使用本机 add-with-carry 指令.非常大的整数的扩展精度库,如 GMP,通常用 asm.
编写
我只在 Pollard Rho 算法中计算“f(x) = (x^2+a) mod n”时才需要“uint256_t”。函数“f”之外的所有变量都是内置类型 __uint128_t.
我为此目的实施了 uint256_t,简单地说:
typedef __uint128_t uint256_t[2];
然后我实现了计算“f()”所需的函数:
__uint128_t set_128(unsigned long h, unsigned long l);
void set_256(uint256_t d, __uint128_t l, __uint128_t h);
void add_128(uint256_t d, uint256_t x, __uint128_t a);
void add_256(uint256_t d, uint256_t x, uint256_t a);
void shl_256(uint256_t d, long s);
void sqr_128(uint256_t d, __uint128_t x);
several print functions and macros for printing 128bit and 256bit numbers
__uint128_t mod_256(uint256_t x, __uint128_t n);
__uint128_t f(__uint128_t x);
在这个要点中找到实现:
https://gist.github.com/Hermann-SW/a20af17ee6666467fe0b5c573dae701d
我确实针对 gmplib 函数对我的代码进行了基准测试,并实现了对所有 gmplib 的加速(经过大量工作),有关详细信息:
https://www.raspberrypi.org/forums/viewtopic.php?f=33&t=311893&p=1873552#p1873552
函数执行 100 万次的纳秒运行时间:
OS: Linux (Debian 10)
CC:海湾合作委员会 8.3
CPU:i7-5775C
在 GCC 中有一个 unsigned __int128
/__int128
,但是有没有办法在 GCC 中有一个 uint256_t
/int256_t
?
我读到 __m256i
好像是英特尔的。是否有任何 header 我可以包含以获取它?
是否像假设的unsigned __int256
一样可用?我的意思是如果你可以给它赋值from/to,比较它们,按位运算等等
它的带符号等价物是多少(如果有)?
编辑 1:
我做到了:
#include <immintrin.h>
typedef __m256i uint256_t;
并编译。如果我可以用它做一些操作,我会在这里更新它。
编辑 2:
发现的问题:
uint256_t m;
int l = 5;
m = ~((uint256_t)1 << l);
输出:
error: can’t convert a value of type ‘int’ to vector type ‘__vector(4) long long int’ which has different size
m = ~((uint256_t)1 << l);
Clang 有 _ExtInt
extended integers 支持除法以外的操作,但 SIMD 对此没有用,因为元素之间有进位 1。其他主流 x86-64 编译器甚至都没有;您需要一个库或其他东西来定义自定义类型,并使用 clang 将使用的相同的 add-with-carry 指令。 (或者纯 C 中效率较低的仿真 2)。
__m256i
是 AVX2 SIMD 4x uint64_t
(或更窄的元素大小,如 8x uint32_t
)。 它不是 256 位标量整数类型,您不能将其用于标量运算,__m256i var = 1
甚至无法编译。 x86 SIMD 不支持宽度大于 64 位的整数,而像 __m128i
和 __m256i
这样的 Intel 内在类型纯粹是针对 SIMD 的。
GCC的__int128
/unsigned __int128
通常使用标量add/adc
,and/or标量mul
/imul
,因为AVX2一般没有帮助为了扩展精度。 (仅适用于元素边界无关紧要的按位 AND/OR/XOR。)
脚注 1:对于 BigInteger 类型,实际上有一定的使用 SIMD 的范围,但仅限于特殊格式。更重要的是,您必须手动选择何时重新归一化(传播进位),因此您的计算必须围绕它进行设计;它不是直接替代品。请参阅 Mysticial 在 Can long integer routines benefit from SSE?
上的回答脚注 2:不幸的是,C 不提供加法/减法的进位运算,因此用 C 编写甚至不方便。sum = a+b
/ carry = sum<a
在没有进位的情况下用于执行,但是用 C 编写一个完整的加法器要困难得多。而且编译器通常会生成垃圾 asm,它不只是在可用的机器上使用本机 add-with-carry 指令.非常大的整数的扩展精度库,如 GMP,通常用 asm.
我只在 Pollard Rho 算法中计算“f(x) = (x^2+a) mod n”时才需要“uint256_t”。函数“f”之外的所有变量都是内置类型 __uint128_t.
我为此目的实施了 uint256_t,简单地说:
typedef __uint128_t uint256_t[2];
然后我实现了计算“f()”所需的函数:
__uint128_t set_128(unsigned long h, unsigned long l);
void set_256(uint256_t d, __uint128_t l, __uint128_t h);
void add_128(uint256_t d, uint256_t x, __uint128_t a);
void add_256(uint256_t d, uint256_t x, uint256_t a);
void shl_256(uint256_t d, long s);
void sqr_128(uint256_t d, __uint128_t x);
several print functions and macros for printing 128bit and 256bit numbers
__uint128_t mod_256(uint256_t x, __uint128_t n);
__uint128_t f(__uint128_t x);
在这个要点中找到实现:
https://gist.github.com/Hermann-SW/a20af17ee6666467fe0b5c573dae701d
我确实针对 gmplib 函数对我的代码进行了基准测试,并实现了对所有 gmplib 的加速(经过大量工作),有关详细信息:
https://www.raspberrypi.org/forums/viewtopic.php?f=33&t=311893&p=1873552#p1873552
函数执行 100 万次的纳秒运行时间: