3

我将 BCD 数的位向左或向右移动以快速乘以或除以 2。这是一个左移的简单示例:

void LShift(unsigned char *arg)
{
   int i, carry=0, temp;
   for(i=2;i>=0;i--)
   {
      temp=(arg[i]<<1)+carry;
      if (temp>9) temp+=6;
      carry=temp>>4;
      arg[i]=temp&0xF;
   }
}

这很好用,如果你给它一个像它一样的数组,{4,5,6}它会返回{9,1,2}.问题是,如果我想移动不止一位,我必须一遍又一遍地调用函数。有没有什么聪明的方法可以一次移动一位以上而不先将 BCD 数转换为十进制?

4

3 回答 3

3

见下文,N 是要移位的位数,假设 N<=3,如果移位超过 3 (N>3),则需要处理多于一位的进位(例如 9*(2^ 4) = 144):

void LShift(unsigned char *arg)
{
   int i, carry=0, temp;
   for(i=2;i>=0;i--)
   {
      temp=(arg[i]<<N)+carry; 
      arg[i]=temp%10;
      temp -= arg[i];
      carry = temp/10;
   }
}

或者,如果您想要更接近原始的东西:

void LShift(unsigned char *arg)
{
   int i, carry=0, temp;
   for(i=2;i>=0;i--)
   {
      temp=(arg[i]<<N)+carry;
      temp+=6 * (temp/10);
      carry=temp>>4;
      arg[i]=temp&0xF;
   }
}

另请注意(在所有版本中,包括原始版本)您可能会留下一个新数字的进位。

于 2013-07-23T05:12:19.107 回答
1

您必须重新设计函数以将要移动的位数作为参数。并使用该参数将 bcd 字节移动多个位置。

void LShift(unsigned char *arg) can be modified to void LShift(unsigned char *arg,int n)

temp=(arg[i]<<n)+carry;
于 2013-07-23T05:28:44.903 回答
0

编写移位逻辑有点复杂,因为进位操作有点麻烦。它变成了看起来非常像移位和加法乘法实现的代码。

void LeftShiftN_1 (unsigned char arg[BCD_DIGITS], unsigned N) {
    int i, j;
    unsigned x, carry;
    unsigned char accum[BCD_DIGITS];
    memset(accum, '\0', sizeof(carry));
    for (i=BCD_DIGITS; i>0; --i) {
        x = arg[i-1];
        x <<= N;
        carry = 0;
        for (j=i; j>=0; --j) {
            carry += accum[j-1] + x % 10;
            x /= 10;
            accum[j-1] = carry % 10;
            carry /= 10;
        }
    }
    memcpy(arg, accum, sizeof(accum));
}

我认为从 BCD 转换并再次转换以进行转换要简单和有效得多。我以直接的方式实现,我确信转换操作可以优化。

void LeftShiftN_2 (unsigned char arg[BCD_DIGITS], unsigned N) {
    int i;
    unsigned accum;
    accum = 0;
    for (i=0; i<BCD_DIGITS; ++i) {
        accum = 10*accum + arg[i];
    }
    accum <<= N;
    for (i=BCD_DIGITS; i>0; --i) {
        arg[i-1] = accum % 10;
        accum /= 10;
    }
}
于 2013-07-23T06:56:02.957 回答