7

我正在处理一项任务,但我不知道如何实现它。我必须创建一个函数sadd(int x, int y)来返回加在一起的数字,除非它溢出(然后只返回最大可能的 int)。我已经能够提出一些涉及强制转换和条件语句的解决方案,但解决方案中不允许使用这些解决方案。只有运算符~ ! ^ + << >> &|

4

2 回答 2

6

对于有符号数的加法,如果将两个相同符号的数字相加并得到具有不同符号的结果,则会发生溢出。由于涉及的范围,当添加两个不同的符号时,不可能产生溢出。

所以,你可以做的是——只看符号位(二进制补码中最重要的一个)——使用异或来判断两个原始数字的符号是否不同,补足,这样你就得到了“0”,如果它们是不同的,“1”表示相同。

然后,您可以对结果与输入之一使用异或。如果它们相同,则为“0”,如果它们不同,则为“1”。

如果两个输入相同但结果不同,则这两个结果一起得到整体“1”,否则为“0”。

然后,您可以使用移位和 OR 的组合来用该值填充整个整数。假设您是 32 位整数,只需设置最低 31 位即可获得最高值的正整数。然后,您可以做的是对任一输入的符号位进行类似的移位和 OR 集。异或结果。如果输入为负数,那将给出最小值整数。

编辑:哦,并使用是否存在溢出的位值,扩展以填充 int,通过将其与溢出时返回的结果相加来选择要返回的值,对其进行补充并与正常值相加加法结果,然后将两者相加(或相加)。

Presto:所有二进制逻辑,没有条件。我假设,因为这是家庭作业,你不想要实际的代码?


九年后,我同意下面@gman 的评论;为了仅使用允许的运算符来实现饱和加法,您必须依赖未定义的行为——而上面的答案隐含地这样做了

这样做的一个重大风险是编译器知道哪些行为是未定义的,并可能在优化期间利用它。底层架构的知识(例如,它是二进制补码,它进行有符号移位)不足以预测编译器的输出。

强大的生产实现是可能的,但需要条件语句,因此不会回答这个问题。

于 2011-03-11T20:02:32.817 回答
2

来自 ARM 网站关于内在函数:

4.1 编译器内在函数

编译器内在函数是编译器提供的函数。它们使您能够轻松地将特定于域的操作合并到 C 和 C++ 源代码中,而无需求助于汇编语言中的复杂实现。C 和 C++ 语言适用于各种各样的任务,但它们不为特定应用领域提供内置支持,例如数字信号处理 (DSP)。在给定的应用程序域中,通常有一系列特定于域的操作必须经常执行。然而,这些操作通常不能在 C 或 C++ 中有效地实现。一个典型的例子是 DSP 编程中常用的两个 32 位有符号二进制补码整数的饱和加法。以下示例显示了饱和加法运算的 C 实现

#include <limits.h>
int L_add(const int a, const int b)
{
    int c;
    c = a + b;
    if (((a ^ b) & INT_MIN) == 0)
    {
        if ((c ^ a) & INT_MIN)
        {
            c = (a < 0) ? INT_MIN : INT_MAX;
        }
    }
    return c;
}

ARM 信息中心

于 2019-04-26T12:58:00.020 回答