假设我们有两个寄存器长度为 2有符号1 的整数,例如a和b。我们想要计算值(a + b) / 2,向上舍入、向下舍入、向零舍入或远离零舍入,无论哪种方式更容易(即我们不关心舍入方向)。
结果是另一个寄存器长度有符号整数(很明显,平均值必须在寄存器长度有符号整数的范围内)。
\n执行此计算最快的方法是什么?
\n您可以选择两个整数最初位于哪个寄存器中,以及平均值最终位于哪个寄存器中。
\n脚注1:对于无符号整数,我们可以用两条指令来完成。尽管循环进位在 Intel CPU 上超过 1 uop,但这可能是最快的方法。但当计数仅为 1 时,只有一对。 关于无符号均值的问答中的答案讨论了效率。
\nadd rdi, rsi\nrcr rdi, 1\nRun Code Online (Sandbox Code Playgroud)\nrdi这两个数字以和开始rsi,平均值以 结束rdi。但对于有符号数,-1 + 3将设置 CF,并将 a 旋转1到符号位。没有给出正确答案+1。
脚注 2:我指定了寄存器长度的有符号整数,这样我们就不能简单地用movsxdorcdqe指令对整数进行符号扩展。
我得到的最接近的解决方案使用四个指令,其中一个rcr在 Intel 上为 3 uops,在 AMD …
我最近了解到整数溢出是C中未定义的行为(侧面问题 - 它是否也是C++中的UB?)
经常在C语言编程,你需要找到两个值的平均值a和b.但是,这样做(a+b)/2会导致溢出和未定义的行为.
所以我的问题是-什么是找到两个值的平均值的正确方法a,并b用C?
中间乘法的值通常需要两倍的位数作为输入.
// Example
int foo(int a, int b, int carry, int rem) {
int2x c; // Some type that is twice as wide at `int`
c = (int2x)a * b + carry;
return (int) (c % rem);
}
Run Code Online (Sandbox Code Playgroud)
考虑到填充的可能性(似乎限制了sizeof()有用性)和非2的补码整数(限制位误),......
以下是否始终创建所需类型?
如果没有,如何编码至少一个合理的解决方案,即使不完全可移植?
#include <limits.h>
#include <stdint.h>
#if LONG_MAX/2/INT_MAX - 2 == INT_MAX
typedef long int2x;
typedef unsigned long unsigned2x;
#elif LLONG_MAX/2/INT_MAX - 2 == INT_MAX
typedef long long int2x;
typedef unsigned long long unsigned2x;
#elif INTMAX_MAX/2/INT_MAX - 2 == …Run Code Online (Sandbox Code Playgroud)