我在我的C++代码的内部循环中使用了128位整数计数器.(不相关背景:实际应用是评估规则网格上的有限差分方程,其中涉及重复递增大整数,甚至64位也不够精确,因为小的舍入累积足以影响答案.)
我将整数表示为两个64位无符号长整数.我现在需要将这些值递增128位常数.这并不难,但你必须手动捕捉低字到高字的进位.
我有这样的工作代码:
inline void increment128(unsigned long &hiWord, unsigned long &loWord)
{
const unsigned long hiAdd=0x0000062DE49B5241;
const unsigned long loAdd=0x85DC198BCDD714BA;
loWord += loAdd;
if (loWord < loAdd) ++hiWord; // test_and_add_carry
hiWord += hiAdd;
}
Run Code Online (Sandbox Code Playgroud)
这是一个紧凑而简单的代码.有用.
不幸的是,这大约是我运行时的20%.这条杀手线就是低价测试.如果我删除它,我显然得到了错误的答案,但运行时开销从20%下降到4%!因此携带测试特别昂贵!
我的问题:C++是否公开了硬件进位标志,即使是作为GCC的扩展?如果实际编译的指令使用最后一个进位指令进行添加,似乎可以在没有上面的测试和添加进位线的情况下完成添加.有没有办法重写test-and-add-carry行以使编译器使用内部操作码?
我想要一个128位整数,因为我想存储两个64位数的乘法结果.在gcc 4.4及以上版本中有没有这样的东西?
我正在尝试生成代码(目前使用clang ++ - 3.8),它添加了两个由多个机器字组成的数字.为了简化目前我只添加128位数字,但我希望能够概括这一点.
首先是一些typedef:
typedef unsigned long long unsigned_word;
typedef __uint128_t unsigned_128;
Run Code Online (Sandbox Code Playgroud)
而"结果"类型:
struct Result
{
unsigned_word lo;
unsigned_word hi;
};
Run Code Online (Sandbox Code Playgroud)
第一个函数f采用两对无符号字并返回结果,作为一个中间步骤,在添加它们之前将这两个64位字放入一个128位字中,如下所示:
Result f (unsigned_word lo1, unsigned_word hi1, unsigned_word lo2, unsigned_word hi2)
{
Result x;
unsigned_128 n1 = lo1 + (static_cast<unsigned_128>(hi1) << 64);
unsigned_128 n2 = lo2 + (static_cast<unsigned_128>(hi2) << 64);
unsigned_128 r1 = n1 + n2;
x.lo = r1 & ((static_cast<unsigned_128>(1) << 64) - 1);
x.hi = r1 >> 64;
return x;
}
Run Code Online (Sandbox Code Playgroud)
这实际上非常好地内联:
movq 8(%rsp), …Run Code Online (Sandbox Code Playgroud) 我正在为128位数字的长流写一个压缩器.我想将数字存储为差异 - 仅存储数字之间的差异而不是数字本身,因为我可以将差异打包在更少的字节中,因为它们更小.
但是,对于压缩,我需要减去这些128位值,对于解压缩,我需要添加这些值.我的编译器的最大整数大小是64位宽.
任何人有任何想法有效地做到这一点?
我正在研究CPU繁重的数值计算应用程序.没有进入很多细节,它是一个计算数学研究项目,涉及为大整数x计算某个函数f(x).
现在,所有内容都是在x64模式下使用C++实现的,使用本机64位整数.这限制了我x <2 ^ 64~1.8*10 ^ 19.我想更进一步,为此,我需要一个执行128位算术的库.它必须非常快.特别是,整数除法应该很快.否则我会坐在这里等待结果直到感恩节.而且我宁愿不重新发明轮子.
我在维基百科上找到了一个大约20个大整数库的列表,但其中大多数似乎都是针对任意精度的数字,这对我的任务来说太过分了,我不需要额外的费用.
有谁知道哪个库可以最快地运行128位整数?
我刚刚设法在Linux Ubuntu 10.04下安装我的cuda SDK.我的显卡是NVIDIA geForce GT 425M,我想用它来解决一些繁重的计算问题.我想知道的是:有没有办法使用一些无符号的128位int var?当使用gcc在CPU上运行我的程序时,我使用的是__uint128_t类型,但是将它与cuda一起使用似乎不起作用.在cuda上有128位整数可以做些什么吗?
非常感谢Matteo Monti Msoft编程
GCC具有128位整数.使用这些我可以让编译器使用mul(或imul只有一个操作数)指令.例如
uint64_t x,y;
unsigned __int128 z = (unsigned __int128)x*y;
Run Code Online (Sandbox Code Playgroud)
生产mul.我用它来创建一个128x128到256的函数(在更新之前,请参阅此问题的结尾,如果您感兴趣,请参阅此代码).
现在我想要进行256位加法,ADC除了使用汇编之外,我还没有找到让编译器使用的方法.我可以使用汇编程序,但我想要内联函数以提高效率.编译器已经生成了一个有效的128x128到256函数(因为我在这个问题的开头解释了)所以我不明白为什么我应该在汇编中重写它(或者编译器已经有效实现的任何其他函数) .
这是我提出的内联汇编函数:
#define ADD256(X1, X2, X3, X4, Y1, Y2, Y3, Y4) \
__asm__ __volatile__ ( \
"addq %[v1], %[u1] \n" \
"adcq %[v2], %[u2] \n" \
"adcq %[v3], %[u3] \n" \
"adcq %[v4], %[u4] \n" \
: [u1] "+&r" (X1), [u2] "+&r" (X2), [u3] "+&r" (X3), [u4] "+&r" (X4) \
: [v1] "r" (Y1), [v2] "r" (Y2), [v3] "r" (Y3), [v4] …Run Code Online (Sandbox Code Playgroud) 我想更多地了解SSE2的功能,并想知道是否可以制作支持加法,减法,XOR和乘法的128位宽整数?
编译器: MinGW/GCC
问题:不允许使用GPL/LGPL代码(GMP或任何bignum库,对于这个问题来说太过分了,因为我已经实现了这个类).
我构建了自己的128位固定大小的整数类(用于游戏引擎,但可以推广到任何用例),我发现当前乘法和除法运算的性能非常糟糕(是的,我有时间,见下文),我想改进(或改变)执行低级数字运算的算法.
当涉及乘法和除法运算符时,与几乎所有其他类似的运算符相比,它们是无法忍受的.
这些是相对于我自己的计算机的近似测量:
Raw times as defined by QueryPerformanceFrequency:
1/60sec 31080833u
Addition: ~8u
Subtraction: ~8u
Multiplication: ~546u
Division: ~4760u (with maximum bit count)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,只是进行乘法比加或减慢很多倍.除法比乘法慢10倍.
我想提高这两个运算符的速度,因为每帧可能会进行非常多的计算(点积,各种碰撞检测方法等).
结构(方法省略)看起来有点像:
class uint128_t
{
public:
unsigned long int dw3, dw2, dw1, dw0;
//...
}
Run Code Online (Sandbox Code Playgroud)
乘法目前使用典型的长乘法方法(在汇编中使我可以捕获EDX输出)同时忽略超出范围的单词(也就是说,mull与16相比,我只做10次).
除法使用移位 - 减法算法(速度取决于操作数的位数).但是,它不是在装配中完成的.我发现有点太难以集合并决定让编译器优化它.
我已经谷歌了几天看着描述算法的页面,例如Karatsuba乘法,高基数除法和牛顿拉普森分部,但数学符号有点太过分了.我想使用其中一些高级方法来加速我的代码,但我必须首先将"希腊语"翻译成可理解的东西.
对于那些可能认为我的努力"过早优化"的人; 我认为这个代码是一个瓶颈,因为非常基本的数学运算本身变得很慢.我可以在更高级别的代码上忽略这种类型的优化,但是这个代码将被调用/使用到足够重要.
我想建议我应该使用哪种算法来改进乘法和除法(如果可能的话),以及关于建议算法如何工作的基本(希望易于理解)解释将受到高度赞赏.
我能够通过将代码内联到operator*=来改进乘法运算,并且它似乎尽可能快.
Updated raw times:
1/60sec 31080833u
Addition: ~8u
Subtraction: …Run Code Online (Sandbox Code Playgroud) 在现代英特尔CPU(核心i7,沙桥)上进行128位移位的最有效方法是什么?
类似的代码在我最内层的循环中:
u128 a[N];
void xor() {
for (int i = 0; i < N; ++i) {
a[i] = a[i] ^ (a[i] >> 1) ^ (a[i] >> 2);
}
}
Run Code Online (Sandbox Code Playgroud)
数据a[N]几乎是随机的.
我在内存中有两个128位的十六进制数字,例如(小端):
x:0x12 0x45 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
y:0x36 0xa1 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Run Code Online (Sandbox Code Playgroud)
我要执行这两个数字之间的无符号乘法,所以我的新数字将是:
z:0xcc 0xe3 0x7e 0x2b 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Run Code Online (Sandbox Code Playgroud)
现在,我知道我可以将半个x和y数字移入rax并rbx注册,例如,执行mul操作,并对另一半执行相同的操作.问题是,通过这样做,我失去了结转,我不知道如何避免这种情况.大约4个小时我面临这个问题,我能看到的唯一解决方案是二进制转换(and< - > shl,1).
你能给我一些关于这个问题的意见吗?
我认为最好的解决方案是占用一个字节的时间.
可以说我有一个由4个32位整数组成的数组,用于存储128位数字
如何在此128位数字上左右移动?
谢谢!