提问人:rogerl 提问时间:3/15/2023 最后编辑:rogerl 更新时间:3/15/2023 访问量:86
将 2**32 平方为 128 位类型失败
Squaring 2**32 into a 128-bit type fails
问:
我希望以下 C 代码会为第一个(确实如此)和第二个(但是,它会产生 )。为什么?(这是在 Intel Core i7 上的 MacOS 上。8, 16
printf
1, 0
0, 0
typedef unsigned long long ll;
typedef unsigned __int128 bigint;
void main() {
ll q;
bigint s;
q = 4294967296ULL; // 2**32
s = q*q;
printf("%d, %d\n", sizeof(ll), sizeof(unsigned __int128));
printf("%lld, %lld\n", s / q, s % q);
}
编辑:将代码修改为以下内容后,结果是相同的(请注意:在原始代码中,我没有尝试打印任何 128 位值)。
void main() {
ll q;
bigint s;
q = 4294967296ULL; // 2**32
s = q*q;
printf("%zu, %zu\n", sizeof(ll), sizeof(unsigned __int128));
printf("%llu, %llu\n", (ll)(s / q), (ll)(s % q));
}
答:
2赞
Eric Postpischil
3/15/2023
#1
In 是一个 64 位 ,乘法是用 64 位算术执行的。由于值为 232,因此数学乘积 2 64 不适合64 位 .它包装模 264,因此计算结果为 0。s = q*q;
q
unsigned long long
q
unsigned long long
因此,被赋值 0,这就是打印的内容(除了注释中指出的转换说明符的问题)。s
printf
您可以通过将至少一个操作数转换为所需类型来请求 128 位算术:
s = (bigint) q * q;
2赞
Ted Lyngmo
3/15/2023
#2
在乘法中,使用 s 而不是 s 完成,因此结果会溢出。要么将操作数强制转换为“从头开始”,要么从头开始。s = q*q;
unsigned long long
unsigned __int128
unsigned __int128
q
unsigned __int128
您还对 使用了错误的转换说明符。用于 .除此之外,除非 gcc 具有用于打印 128 位类型的扩展,否则您需要找到另一种打印方式。printf
%zu
sizeof
printf
例:
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
typedef unsigned __int128 ubigint;
void print(ubigint x) {
// print top 64 bits first and the lower 64 bits last:
printf("%016" PRIx64 "%016" PRIx64, (uint64_t)(x >> 64), (uint64_t)x);
}
int main() {
ubigint q; // correct type
ubigint s;
q = 4294967296ULL;
s = q * q; // no overflow anymore
printf("%zu, %zu\n", sizeof(long long), sizeof(ubigint));
print(s);
putchar('\n');
print(s / q);
putchar('\n');
print(s % q);
putchar('\n');
}
输出
8, 16
00000000000000010000000000000000
00000000000000000000000100000000
00000000000000000000000000000000
2赞
Bodo
3/15/2023
#3
计算的类型会导致溢出并截断为 的类型。然后将截断的结果分配给具有更大类型的结果。s = q*q;
q
q
s
强制转换为较大的类型以强制在较大的类型中进行计算。s
s = (bigint)q * q;
或者将 的值赋给较大类型的变量,并将其用于计算。q
s = q;
s = s * s;
1赞
0___________
3/15/2023
#4
您需要投射:
typedef unsigned long long ll;
typedef unsigned __int128 bigint;
int main(void)
{
ll q;
bigint s,d;
q = 4294967296ULL; // 2**32
s = (bigint)q*q;
d = q*q;
printf("%lld, %lld\n", (ll)(s / q), (ll)(s % q));
printf("%lld, %lld\n", (ll)(d / q), (ll)(d % q));
}
评论
printf
sizeof
printf
__int128
s / q
s % q
long long
unsigned
printf
%zu
sizeof