7

希望有符号整数在它们变得太大时溢出。如果不使用下一个最大的数据类型(或者当我已经在 int128_t 时),我如何实现这一点?

例如,使用 8 位整数 19*12 通常是 260,但我想要1 11 10 01 00截断第 9 位的结果,即 -27。

4

7 回答 7

7

有符号溢出在 C 中是未定义的,这是真实的

一种解决方案如下:

signed_result = (unsigned int)one_argument + (unsigned int)other_argument;

上述解决方案在从unsigned到的最终转换中涉及实现定义的行为,int但不调用未定义的行为。对于大多数编译平台的实现定义选择,结果正是您期望的二进制补码结果。

最后,针对众多平台之一的优化编译器,在这些平台上,实现定义的选择会强制编译器为您提供您期望的行为,并将上述代码编译为明显的汇编指令。

或者,如果您使用 gcc,那么选项-fwrapv/-fno-strict-overflow可能正是您想要的。它们为签名溢出环绕的标准提供了额外的保证。我不确定两者之间的区别。

于 2010-11-21T22:48:18.323 回答
2

只要您可以访问与您的unsigned类型具有相同宽度的signed类型(即多一个值位),就可以以正确的标准 C 方式执行此操作。演示int64_t

int64_t mult_wrap_2scomp(int64_t a, int64_t b)
{
    uint64_t result = (uint64_t)a * (uint64_t)b;

    if (result > INT64_MAX)
        return (int64_t)(result - INT64_MAX - 1) - INT64_MAX - 1;
    else
        return (int64_t)result;
}

这不会产生任何有问题的中间结果。

于 2010-11-22T01:30:33.870 回答
2

根据 C 和 C++ 标准,有符号整数溢出是未定义的。如果不考虑特定平台,就无法完成您想要的。

于 2010-11-21T22:26:39.083 回答
1

您可以围绕 int 创建一个目标包装器,但这会涉及大量开销代码。

于 2010-11-21T22:30:00.877 回答
1

假设二进制补码有符号整数算术(如今这是一个合理的假设),对于加法和减法,只需转换为无符号数即可进行计算。对于乘法和除法,确保操作数为正数,强制转换为无符号,计算并调整符号。

于 2010-11-21T22:47:32.510 回答
0

听起来您想做无符号整数运算,然后将结果填充到有符号整数中:

unsigned char a = 19;
unsigned char b = 12;

signed char c = (signed char)(a*b);

应该给你你正在寻找的东西。如果没有,请告诉我们。

于 2010-11-21T22:46:21.180 回答
-1

使用更大的数据类型。使用GMP,您将拥有您可能需要的所有空间。

于 2010-11-21T22:41:40.027 回答