【问题标题】:Long Hand Multiplication In C++C++ 中的长手乘法
【发布时间】:2012-12-02 05:08:30
【问题描述】:

我正在尝试为存储在两个数组BeforeDecimal1 and BeforeDecimal2 中的 8 位二进制数实现长手乘法方法。问题是我总是得到错误的结果。我试图找出问题,但无法做到。代码如下:

这是一个比前一个更精致的代码。它给了我结果,但结果不正确。

int i=0,carry=0;

while(true)
{
    if(BeforeDecimal2[i]!=0)
        for(int j=7;j>=0;j--)
        {
            if(s[j]==1 && BeforeDecimal1[j]==1 && carry==0)
            {
                cout<<"Inside first, j= "<<j<<endl;
                carry=1;
                s[j]=0;
            }
            else
                if(s[j]==1 && BeforeDecimal1[j]==0 && carry==1)
                {
                    cout<<"Inside second, j= "<<j<<endl;
                    carry=1;
                    s[j]=0;
                }
                else
                    if(s[j]==0 && BeforeDecimal1[j]==0 && carry==1)
                    {
                        cout<<"Inside third, j= "<<j<<endl;
                        carry=0;
                        s[j]=1;
                    }
                    else
                        if(s[j]==0 && BeforeDecimal1[j]==0 && carry==0)
                        {
                            cout<<"Inside fourth, j= "<<j<<endl;
                            carry=0;
                            s[j]=0;
                        }
                        else
                            if(s[j]==0 && BeforeDecimal1[j]==1 && carry==0)
                            {
                                cout<<"Inside fifth, j= "<<j<<endl;
                                carry=0;
                                s[j]=1;
                            }

                            else
                                if(s[j]==1 && BeforeDecimal1[j]==1 && carry==1)
                                {
                                    //cout<<"Inside fifth, j= "<<j<<endl;
                                    carry=1;
                                    s[j]=1;
                                }
                                else
                                    if(s[j]==1 && BeforeDecimal1[j]==0 && carry==0)
                                    {
                                        //cout<<"Inside fifth, j= "<<j<<endl;
                                        carry=0;
                                        s[j]=1;
                                    }
                                    else
                                        if(s[j]==0 && BeforeDecimal1[j]==1 && carry==1)
                                        {
                                            //cout<<"Inside fifth, j= "<<j<<endl;
                                            carry=1;
                                            s[j]=0;
                                        }

        }

        for(int h=7;h>=0;h--)
        {
            if(h==0)
            {
                BeforeDecimal1[0]=0; // that is inserting zeros from the right
            }
            else
            {
                BeforeDecimal1[h]=BeforeDecimal1[h-1];
                BeforeDecimal1[h-1]=0;
            }

        }
    if(i==3)
        break;

    i++;
}

问候

【问题讨论】:

  • 要么在调试器中单步执行它,要么在代码中添加大量输出语句,以便找出其执行与应有的不同之处。

标签: c++ arrays binary multiplication


【解决方案1】:

也许最容易备份并从存储为 8 位二进制数的 8 位二进制数开始。就像我们做十进制乘法一样,我们从多个数字开始。我们将乘以这些单个数字的值,并将它们加在一起以获得最终结果。区别(或一个明显的区别)是,因为我们使用二进制工作,我们所有的数字都代表 2 的幂,所以我们可以通过简单地对输入进行位移来获得每个中间结果。

由于它是二进制的,我们对于每个数字只有两种可能性:如果是 0,那么我们需要将另一个数字加 0 乘以左移适当的位数。显然,0 次还是 0,所以在这种情况下我们什么也不做。另一种可能性是我们有一个 1,在这种情况下,我们将其他数字的 1 与左移适当的位数相加。

例如,让我们考虑 17 x 5 或(二进制)10001 x 101。

     10001
       101
    ------
     10001
 + 1000100
  --------
 = 1010101      

将其转换为更易识别的值,我们得到 0x55 或 85d

在代码中,这个过程相当简短。从结果 0 开始。检查是否设置了一个操作数中的最低有效位。如果是这样,则将另一个操作数添加到结果中。将一个操作数右移一点,将另一个操作数左移一点,然后重复直到右移的操作数等于 0:

unsigned short mul(unsigned char input1, unsigned char input2) { 
    unsigned short result = 0;

    while (input2 != 0) {
        if (input2 & 1)
            result += input1;
        input1 <<= 1;
        input2 >>= 1;
    }
    return result;
}

如果要处理有符号数,通常最简单的方法是分别计算结果的符号,然后对绝对值进行乘法运算。

【讨论】:

  • 我有这个想法用移位和东西来做,但我需要首先将输入转换为二进制并将每个二进制转换存储在单独的数组中,然后在数组上应用长手乘法,这是一个混乱。感谢您的好回答,但不幸的是我无法利用它:(
  • @Alfred:虽然您显然不能完全按原样使用它,但我怀疑您可以做类似的事情,但查看数组中的单独元素而不是在一个字节中移动位。跨度>
  • 我尝试使用数组来实现您的想法。但答案仍然不正确。有什么我想念的吗
  • @Jerry 你能告诉我我错过了什么吗?我没有得到正确的结果
【解决方案2】:

以下代码行有问题

if(reverse==0)
{
    totalReverse=totalReverse-1;
    reverse=totalReverse;
}

在内部 for 循环(基于索引 j)的一些迭代之后,reverse 的值应该变为负数,当 reverse 小于 3 时,应该抛出异常。

您是否在不处理异常的情况下运行此代码?

【讨论】:

  • 这不是问题。发布代码时出错,reverse 和 totalReverse 是 14 位大小的两倍。仍然由于某种原因,我得到的结果为零
  • 您使用的是 8 位数字,因此双倍大小应为 16 位。
  • 哦,是的,我的错。我知道在实现长手乘法的代码中存在一些逻辑错误。你能通知我吗
【解决方案3】:

对我来说,这闻起来像 shift and add。是否要求您只能使用模拟逻辑门的操作?

对于您的full adder,您有 3 个输入 s(s[j])、b(BeforeDecimal1[j])、c(carry) 和两个输出 ns(new s[j])、nc(新进位) 表格是这样的

s  b  c ns nc
0  0  0  0  0 handled in v5 clause 4
0  0  1  1  0 handled in v5 clause 3
0  1  0  1  0 handled in v6 clause 5
0  1  1  0  1
1  0  0  1  0
1  0  1  0  1 handled in v5 clause 2
1  1  0  0  1 handled in v5 clause 1
1  1  1  1  1

您的代码仅涵盖这 8 个子句中的 4 个(现在是 5 个)

为了避免丑陋的 if-else-if rake,我建议使用临时结果变量(进位和 s 在下一个 if 子句中仍然有效)

当您分析表格时,您也可以这样做(伪布尔表示法)

nc = s && b || s && c || b && c;
ns = s XOR b XOR c;              // there is no XOR in C++: axb = a&&!b || !a&&b

算术符号

nc = (s + b + c) / 2;
ns = (s + b + c) % 2;



// [...]
for(int j=7;j>=0;j--)
{
    // start changed code
    const int sum = s[j] + BeforeDecimal1[j] + carry;
    s[j]=sum % 2;
    carry=sum / 2;
    // end changed code
}
// [...]

这是一个很好的模拟你的问题Sequential Multiplication

【讨论】:

  • 这是最简单的方法,但不是必需的
  • Jeffery Coffin 提出的长手乘法的想法。我正在尝试在包含二进制数的数组上实现它
  • 我明白这一点。我指出您的 if-else-if 子句仅涵盖所有输入可能性中的四个(现在五个)。你必须涵盖所有八个。其次,我指出这种 if-else-if 结构是糟糕的设计。有几种方法可以改进它。例如,您可以使用上面的算术符号。这两行(加上另外两行存储在 s, c 中)替换了大约 50 行(加上一些缺失子句)的整个 if-else-if 构造(从第 6 行开始)
  • 对不起,我没听明白。编辑我的问题以提出您的想法。
  • 谢谢。但问题仍然存在。即使使用您的代码。目前我没有做代码优化,我只是按原样实现这个想法,一旦我得到正确的结果,我会在以后做优化
【解决方案4】:

除非您的要求另有明确说明,否则您的问题或到目前为止的任何 cmets 都不清楚,否则没有必要处理位数组。字节数组在空间和时间上都更加高效。

您也不需要这种详尽无遗的案例。唯一的特殊情况是任一操作数为零,即a[i]|b[i] == 0,当

result[i] = carry;
carry = 0;

所有其他情况可由以下人员处理:

result[i] = a[i]*b[i]+carry;
carry = (result[i] >>> 8) & 1;
result[i] &= 0xff;

BeforeDecimal1BeforeDecimal2 这两个名字我也看不出有什么意义。

【讨论】:

  • 感谢您的回答,输入将是浮点数,但为了使程序正常工作,我将输入作为int,这个BeforeDecimal表示“。”之前的数字的一部分
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-25
  • 2015-05-24
  • 1970-01-01
  • 2010-09-16
  • 2020-02-27
相关资源
最近更新 更多