【问题标题】:Multiplication of two unsigned integers as an unsigned int [duplicate]将两个无符号整数相乘作为无符号整数 [重复]
【发布时间】:2020-10-26 00:45:29
【问题描述】:

我有以下 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;
}

typedef struct{ uint x; uint c; } mwc64x_state_t;

enum{ MWC64X_A = 4294883355U };
enum{ MWC64X_M = 18446383549859758079UL };

这个函数是我在网上找到的一个包的一部分。我很想知道 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

谢谢,

【问题讨论】:

  • @kaylum,部分。我怀疑它通过使用模 2^32 进行翻转来计算乘法,但在我的示例中,我应该在上面的第三次迭代中得到 Xn=1207281664,而不是 1207281075。我不明白为什么!跨度>
  • 你用的是什么编译器? MWC64X_AMWC64X_M 的实际大小是多少?像printf( "sizeof( MWC64X_M ) = %zd\n", sizeof( MWC64X_M ) ) 这样的东西实际发出的大小。它们的实际值是多少?仅乘法的实际结果是什么?
  • @AndrewHenle MWC64X_M 是 8 个字节,MWC64X_A 是 4 个字节。我在 LLVM clang 9 之上使用带有 CL1.2 的 OpenCL 编译器作为编译器。我对输入 (X= 4294799414, C=1) 的迭代得到的实际结果是 (Xn = 1207281075, Cn = 4294715476)
  • 目前尚不清楚您如何认为应该在第三次迭代中获得 1207281664。我通过独立计算得到1207281075(见我的答案)。

标签: c integer-overflow unsigned-integer


【解决方案1】:

常数 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。

【讨论】:

  • 我计算了 (4294883355U* 4294799414)%MAX_UNSIGNED_INT 这给了我 1207281664 的值。我不明白为什么我得到的值与你得到的不同,因为我所做的只是在计算结束时取模,而你在乘法之前取模。
  • 我猜你在乘法 4294883355U*4294799414 中丢失了精度。我在 Excel 中得到了相同的最终结果,它将 4294883355*4294799414 显示为 18445662516252400000.00 (注意小数点;我认为它在内部切换到浮点表示)。最终结果是 1207281664 = 589493 * 2048,所以看起来我们在乘以 4294883355*4294799414 时损失了 10 个二进制位的精度。 (结果应该能被 2 整除,但不能被 4 整除。)
猜你喜欢
  • 1970-01-01
  • 2013-06-02
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-09
  • 1970-01-01
相关资源
最近更新 更多