📌  相关文章
📜  如何在C / C++中不使用算术运算运算符的情况下将两个整数相加?

📅  最后修改于: 2021-05-30 04:49:43             🧑  作者: Mango

给定两个整数a和b,我们如何在不使用+,-,++,-,…等运算符的情况下求和a + b?

方法1(使用指针)

一种有趣的方式是:

// May not work with C++ compilers and
// may produce warnings in C.
  
// Returns sum of 'a' and 'b'
int sum(int a, int b) 
{
    char *p = a;
    return (int)&p[b];
}

尽管乍一看很尴尬,但我们可以轻松地了解正在发生的事情。首先,我们创建了一个指针p。指针的值是一个内存地址。在这种情况下,p的值是地址a。
图像
请记住:p指向位置a。在该示例中,如果我们想知道位置a(999)的值,请询问* p。如果我们想知道变量a(41)的地址,请询问&a。

如果我们评估p [b],我们将获得位置p + b的内存值。实际上,我们对&p [b]求值,女巫等于在不访问其值的情况下获取地址p + b。由于p = a,&p [b]将返回地址a + b。

我们不想返回内存地址(int *)。我们要返回一个整数(int)。因此,我们将&p [b]转换为int。

如果将p的类型从char *更改为int *会发生什么?让我修正我之前说的内容:当我们评估p [b]时,我们不会评估p + b。我们评估p + sizeof(* p)* b。为什么?想象一下这个例子:int类型的变量在内存中占据四个位置。

总和2

sizeof(* p)考虑每个变量在内存中占据的位置数量。

我们要评估p + b。换句话说,我们希望sizeof(* p)等于1。因此,如果* p是一个字符,我们很高兴。

方法2(使用按位运算运算符)

让我们看一下总和的真值表(现在暂时忽略进位):

仔细看,我们发现总和与异或的真值表是相同的。仅当输入不同时为1。

现在,我们如何检测进位?让我们看一下进位的真值表。

总和3

仔细看,我们发现总和与异或的真值表是相同的。仅当输入不同时为1。

现在,我们如何检测进位?让我们看一下进位的真值表。

总和4

再仔细看一次,我们注意到进位的和逻辑与的真值表是相同的。现在,我们必须将a&1向左移动并求和a ^ b。但是,这些操作也可能带有进位。没问题,只需将a ^ b与a和1递归左移即可。

// Returns sum of a and b using bitwise
// operators.
int sum(int a, int b) 
{
    int s = a ^ b;
    int carry = a & b;
  
    if (carry == 0) return s;
    else return sum(s, carry << 1);
}

此解决方案已在此处讨论。

方法3(使用printf)

让我们记住一些事实:

  • printf返回成功打印的字符数。
  • 说明符%* c请求两个参数:第一个是自定义宽度,第二个是字符。例如,printf(“%* c”,5,’a’)将打印“ a”。
  • 特殊字符’\ r’从输出字符串的开头返回光标。例如,printf(“ abcd \ r12”)将打印“ 12cd”。

记住这一点,我们可以理解此函数:

// Returns sum of a and b using printf
// Constraints: a, b > 0.
int sum(int a, int b) 
{
    return printf("%*c%*c", a, '\r', b, '\r');
}

此解决方案已在此处讨论。