C 将两个无符号整数相乘为无符号整数

C 将两个无符号整数相乘为无符号整数,c,integer-overflow,unsigned-integer,C,Integer Overflow,Unsigned Integer,我有下面的C函数,它在GPU上对32位无符号整数执行一些乘法和位移位。假设我从值X=0和C=2开始: void MWC64X_Step(global mwc64x_state_t *s) { uint X=s->x, C=s->c; printf("X = %u, C = %u, ", X, C); uint Xn=MWC64X_A*X+C; uint carry=(uint)(Xn<C); //The (Xn<C) w

我有下面的C函数,它在GPU上对32位无符号整数执行一些乘法和位移位。假设我从值X=0和C=2开始:

void MWC64X_Step(global mwc64x_state_t *s)
{
    uint X=s->x, C=s->c;
    printf("X = %u, C = %u, ", X, C);
    uint Xn=MWC64X_A*X+C;
    uint carry=(uint)(Xn<C); //The (Xn<C) will be zero or one for scalar
    uint Cn=mad_hi(MWC64X_A,X,carry);
    printf("Xn = %u, Cn = %u, ", Xn, Cn);
    s->x=Xn;
    s->c=Cn;
}
这个函数是我在网上找到的一个包的一部分。我很好奇,如果X变得非常大,大约是
2^32
,因为Xn被声明为无符号整数(在我的平台上是32位),那么它是如何计算的?Xn是保持模MAX_INT_32的值,还是执行其他操作

我从X=0和C=2的连续运行中得到的结果:

Xn = 2, Cn = 0, 
Xn = 4294799414, Cn = 1, 
Xn = 1207281075, Cn = 4294715476. <--- 3rd iteration
Xn=2,Cn=0,
Xn=4294799414,Cn=1,

Xn=1207281075,Cn=4294715476 常数
MWC64X_A=4294883355U
与-83941 mod 2^32一致

2*(-83941)+0=-167882,与4294799414 mod 2^32一致


(-167882)*(-83941)=14092182962,与1207281074 mod 2^32(根据Excel)和1207281074+1=1207281075一致。所以你得到的结果与每次取模2^32的乘法结果是一致的。

@kaylum,部分。我怀疑它是通过使用模2^32来计算乘法的,但在我的示例中,我应该在上面的第三次迭代中得到Xn=1207281664,而不是1207281075。我不明白为什么!你在用什么编译器?
MWC64X\u A
MWC64X\u M
的实际尺寸是多少?像printf(“sizeof(MWC64X_M)=%zd\n”,sizeof(MWC64X_M))这样的东西实际发出的大小。它们的实际价值是什么?乘法的实际结果是什么?@AndrewHenle MWC64X_M是8字节,MWC64X_A是4字节。我使用一个OpenCL编译器,在LLVMClang9的基础上使用CL1.2作为编译器。对于输入(X=4294799414,C=1)的迭代,我得到的实际结果是(Xn=1207281075,Cn=4294715476)。不清楚您如何计算在第三次迭代中应该得到1207281664。我通过独立计算得到了1207281075(见我的答案)。我计算了(4294883355U*4294799414)%MAX_UNSIGNED_INT,得到了1207281664的值。我不明白为什么我得到的值与你得到的不同,因为我所做的只是在计算结束时取模,而你在乘法之前取你的模。我猜你在乘法中失去了精度
4294883355U*4294799414
。我在Excel中得到了相同的最终结果,它显示4294883355*4294799414,与18445662524240000.00相同(注意小数点;我认为它在内部切换为浮点表示)。最终的结果是1207281664=589493*2048,所以当乘以4294883355*4294799414时,我们似乎失去了10个二进制精度位。(结果应该可以被2整除,但不能被4整除。)谢谢@DavidK!
Xn = 2, Cn = 0, 
Xn = 4294799414, Cn = 1, 
Xn = 1207281075, Cn = 4294715476. <--- 3rd iteration