Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ N位带环绕的整数减法_C++_Math_Bit Manipulation_Subtraction - Fatal编程技术网

C++ N位带环绕的整数减法

C++ N位带环绕的整数减法,c++,math,bit-manipulation,subtraction,C++,Math,Bit Manipulation,Subtraction,基本上,使用减法溢出整数时的行为,但对于给定的位数。显而易见的方法是,假设一个有符号的整数: template <int BITS> int sub_wrap(int v, int s) { int max = (1<<(BITS)); v -= s; if (v < -max) v += max*2; // or if branching is bad, something like: // v += (max*2) * (v < -ma

基本上,使用减法溢出整数时的行为,但对于给定的位数。显而易见的方法是,假设一个有符号的整数:

template <int BITS>
int sub_wrap(int v, int s) {
  int max = (1<<(BITS));
  v -= s;
  if (v < -max) v += max*2;
  // or if branching is bad, something like:
  // v += (max*2) * (v < -max)
  return v;
}

// For example subtracting 24 from -16 with 5 bit wrap,
// with a range of -32, 31
sub_wrap<5>(-16, 28); -> 20
模板
int sub_包裹(int v,int s){

int max=(1我想这应该是可行的:

 struct bits
 {
     signed int field : 5;
 };

 bits a = { -16 };     
 bits b = {  28 };

 bits c = { a.field - b.field };
 std::cout << c.field << std::endl;
struct位
{
签名整型字段:5;
};
位a={-16};
位b={28};
位c={a.field-b.field};

std::cout用于无符号算术,并屏蔽结果,例如:

template<int bits>
unsigned
sub_wrap( unsigned v, unsigned s )
{
    return (v - s) & ((1 << bits) - 1);
}

鉴于此,
sub-wrap(-16,28)
给出了
-12
(这是正确的,注意
28
不能用5位的有符号整数表示);
sub-wrap(-16,28)
给出了
20
这模拟了一个n位整数运算:

#include <iostream>
#include <cstdlib>

template< typename T >
T sub_wrap(T a, T b, int nBits)
{
        T topBit, mask, tmp;

        topBit=T(1) << (nBits-1);
        mask=(topBit << 1)-1;
        tmp=((a&mask)+((~b+1)&mask))&mask;
        if (tmp & topBit) tmp=-((~tmp&mask)+1);

        return tmp;
}

int main(int argc, char* argv[])
{
        std::cout << sub_wrap< int >(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]))
                << std::endl;
        return 0;
}

似乎您将类型大小计算错了1位。

以下是我在不使用条件分支和乘法的情况下的操作方法:

#include <stdio.h>

// Assumptions:
// - ints are 32-bit
// - signed ints are 2's complement
// - right shifts of signed ints are sign-preserving arithmetic shifts
// - signed overflows are harmless even though strictly speaking they
//   result in undefined behavior
//
// Requirements:
// - 0 < bits <= 32
int sub_wrap(int v, int s, unsigned bits)
{
  int d = v - s;
  unsigned m = ~0u >> (32 - bits);
  int r = d & m | -((d >> (bits - 1)) & 1) & ~m;
  return r;
}

#define BITS 2

int main(void)
{
  int i, j;
  for (i = -(1 << (BITS - 1)); i <= (1 << (BITS - 1)) - 1; i++)
    for (j = -(1 << (BITS - 1)); j <= (1 << (BITS - 1)) - 1; j++)
      printf("%d - %d = %d\n", i, j, sub_wrap(i, j, BITS));
  return 0;
}

您还需要检查
v>=max
。从-32到31的范围需要6位,而不是5位。这完全取决于您的观点。我只是习惯于表示不包括我当前使用的代码中的符号的位数,但我想这会让人困惑。另一方面,赋值回来,然后从
返回字段truct
可以工作。这可能是有符号值的最简单的解决方案。@JamesKanze:我不知道你的确切意思,但这似乎表明它不工作:如前所述,它不工作,但如果你声明位字段
signed int
,将计算值赋回它,然后从位字段返回值,它将返回可以工作(对我来说也可以)。默认情况下位字段是有符号的还是无符号的是实现定义的。@interjay:spot-on(§9.6,sub-3)“固定的,你的代码永远不会产生负值,这似乎是OP想要的。”亚历克斯从他的例子中判断,这就是他想要的,但是根据他所写的,它并不清楚。我的代码是我所认为的“经典”的解决方案,用于在范围>代码> [0,2^ n ]的模运算。
,但对于模运算,我会使用无符号整数类型。@然而,sehe的建议非常聪明,也适用于有符号类型。+1用于尝试更多,并且(a)指出我不应该从OP的面值(b)处获取样本,该样本显示位字段可以根据常量模板参数变化(weehoo:永远不要低估C++的威力)@JamesKanze:从OP的代码来看,结果范围也应该包括负数。请参见
if(v<-max)v+=max*2;
。感谢这个清晰的答案,并为这个令人困惑的例子感到抱歉。我提出了这将如何执行的问题。
template<int bits>
int
sub_wrap( int v, int s )
{
    struct Bits { signed int r: bits; } tmp;
    tmp.r = v - s;
    return tmp.r;
}
#include <iostream>
#include <cstdlib>

template< typename T >
T sub_wrap(T a, T b, int nBits)
{
        T topBit, mask, tmp;

        topBit=T(1) << (nBits-1);
        mask=(topBit << 1)-1;
        tmp=((a&mask)+((~b+1)&mask))&mask;
        if (tmp & topBit) tmp=-((~tmp&mask)+1);

        return tmp;
}

int main(int argc, char* argv[])
{
        std::cout << sub_wrap< int >(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]))
                << std::endl;
        return 0;
}
$ ./sim 5 6 4
-1
$ ./sim 7 3 4
4
$ ./sim 7 -1 4
-8
$ ./sim -16 28 4
4
$ ./sim -16 28 5
-12
$ ./sim -16 28 6
20
#include <stdio.h>

// Assumptions:
// - ints are 32-bit
// - signed ints are 2's complement
// - right shifts of signed ints are sign-preserving arithmetic shifts
// - signed overflows are harmless even though strictly speaking they
//   result in undefined behavior
//
// Requirements:
// - 0 < bits <= 32
int sub_wrap(int v, int s, unsigned bits)
{
  int d = v - s;
  unsigned m = ~0u >> (32 - bits);
  int r = d & m | -((d >> (bits - 1)) & 1) & ~m;
  return r;
}

#define BITS 2

int main(void)
{
  int i, j;
  for (i = -(1 << (BITS - 1)); i <= (1 << (BITS - 1)) - 1; i++)
    for (j = -(1 << (BITS - 1)); j <= (1 << (BITS - 1)) - 1; j++)
      printf("%d - %d = %d\n", i, j, sub_wrap(i, j, BITS));
  return 0;
}
-2 - -2 = 0
-2 - -1 = -1
-2 - 0 = -2
-2 - 1 = 1
-1 - -2 = 1
-1 - -1 = 0
-1 - 0 = -1
-1 - 1 = -2
0 - -2 = -2
0 - -1 = 1
0 - 0 = 0
0 - 1 = -1
1 - -2 = -1
1 - -1 = -2
1 - 0 = 1
1 - 1 = 0