Javascript 如何在JS中执行逐位乘法

Javascript 如何在JS中执行逐位乘法,javascript,Javascript,我想做一个函数,将数字逐位相乘,就像我们在学校做的那样。例如,在445*456中,我们首先将5乘以6,然后乘以4,再乘以4。然后,我们用4乘以5,依此类推。我想这样做是为了得到很长乘法的字符串答案 这里,numArray是存储在数组中的数字,例如563是[5,6,3]; 类似地,另一个数字可以是例如621,其被转换为[6,2,1] for(var i = 1; i <= anotherNumArray.length; i++) { var multiplier = a

我想做一个函数,将数字逐位相乘,就像我们在学校做的那样。例如,在445*456中,我们首先将5乘以6,然后乘以4,再乘以4。然后,我们用4乘以5,依此类推。我想这样做是为了得到很长乘法的字符串答案

这里,numArray是存储在数组中的数字,例如563是[5,6,3]; 类似地,另一个数字可以是例如621,其被转换为[6,2,1]

   for(var i = 1; i <= anotherNumArray.length; i++) {
        var multiplier = anotherNumArray[anotherNumArray.length-i]
        for(var j = 1; j <= numArray.length; j++) {
            var multiplicand = numArray[numArray.length-j]
            answer.unshift(multiplicand*multiplier);
   }

for(var i=1;i这个问题比前面提到的更复杂

假设实际的“长乘法”模拟,即只允许数字乘法和求和,请参见下面的注释和工作代码

首先,代码忽略了两个数字的乘法将溢出并产生一个非零进位值的事实,该进位值应与下一次乘法相加

第二,正如我们在学校里所说的,对于每一个数字,我们都会收到一个新的乘法结果和第二个数的所有其他数字。我们最终需要对这些乘法结果求和

下面的代码适用于非负十进制数。它可以被简化,但它试图保持初始算法的精神

// parameters
const lhs = "445";
const rhs = "456";

// utilities
const createZeros = length => new Array(length).fill(0);
const padArrayEnd = (length, padding, array) => [...array, ...createZeros(length - array.length)];
const last = array => array[array.length - 1];

// given a carray and an array of digits, add the carry to the last digit.
// if the result overflows, add the remainder as a new digit instead
// example;
//   array = [3, 4, 5]; addCarry(2, array); array == [3, 4, 7]
//   array = [3, 4, 9]; addCarry(2, array); array == [3, 4, 0, 1]
function addCarry(carry, digits) {
    if (carry == 0) {
        return;
    }

    let value = last(digits) + carry;
    if (value > 10) {
        digits[digits.length - 1] = 0;
        digits.unshift(value % 10);
    } else {
        digits[digits.length - 1] = value;
    }
}

console.log({ message: "start", lhs, rhs });

// state
const answer = [];
const entries = [];
let carry = 0;

// perform digit by digit multiplication.
// remember that the result array for each digit should have N leading zeros, where N is the position of that digit.
// this is the reason we keep an array of entries. each entry, is the result array corresponding to that digit
for(let lcur = 0; lcur < lhs.length; lcur++) {
    const leftDigit = lhs[lhs.length - 1 - lcur];

    // the multiplications entry
    const multiplications = createZeros(lcur);

    for(let rcur = 0; rcur < rhs.length; rcur++) {
        const rightDigit = rhs[rhs.length - 1 - rcur];

        // perform multiplication, but notice that in case of overflow we keep
        // only the ones, and remember carry for next iteration
        const times = (leftDigit * rightDigit) + carry;
        const ones = times % 10;
        carry = Math.floor(times / 10);

        multiplications.unshift(ones);
        console.log({ message: "step", expr: `${leftDigit} * ${rightDigit}`, times, ones, carry });
    }

    if (carry != 0){
        multiplications.unshift(carry);
        carry = 0;
    }

    // update entries
    entries.push(multiplications); 
    console.log({ message: "entry", multiplications });
}

// add the final carry
addCarry(carry, last(entries));

console.log({ message: "entries", entries });

// sum all entries with carries
const maxLength = entries
    .map(entry => entry.length)
    .reduce((acc, entry) => Math.max(acc, entry), 0);

// for convinience, reverse all entries - this can by bypassed with messing around with indices
entries.forEach(entry => entry.reverse());

carry = 0;
for (let idx = 0; idx < maxLength; ++idx) {
    const sum = entries
        .map(entry => entry[idx] || 0)
        .reduce((acc, value) => acc + value, carry);

    const ones = sum % 10;
    carry = Math.floor(sum / 10);

    answer.unshift(ones);
    console.log({ message: "summation", sum, ones, carry, answer });
}

// add final summation carry
// remember that we reversed stuff before, reverse back
// answer.reverse()
addCarry(carry, answer);

// finalize a result 
const result = answer.join("");
const expected = (parseInt(lhs) * parseInt(rhs)).toString(); // string for some reason
console.log({ message: "finish", expr: `${lhs} * ${rhs} = ${answer.join("")}`, answer, expected });
//参数
const lhs=“445”;
const rhs=“456”;
//公用事业
const createZeros=length=>新数组(长度).fill(0);
常量padarayend=(长度、填充、数组)=>[…数组,…创建零(长度-数组.length)];
const last=array=>array[array.length-1];
//给定一个进位和一个数字数组,将进位添加到最后一个数字。
//如果结果溢出,则将余数添加为新数字
//榜样;
//数组=[3,4,5];addCarry(2,array);数组==[3,4,7]
//数组=[3,4,9];addCarry(2,数组);数组==[3,4,0,1]
函数addCarry(进位,数字){
如果(进位==0){
返回;
}
让值=最后(位数)+进位;
如果(值>10){
位数[位数.长度-1]=0;
数字。取消移位(值%10);
}否则{
数字[digits.length-1]=值;
}
}
log({消息:“开始”,lhs,rhs});
//陈述
常数回答=[];
常量条目=[];
让进位=0;
//执行逐位乘法。
//请记住,每个数字的结果数组应该有N个前导零,其中N是该数字的位置。
//这就是我们保留条目数组的原因。每个条目都是对应于该数字的结果数组
对于(设lcur=0;lcurentry.length)
.reduce((acc,entry)=>数学最大值(acc,entry),0);
//为了方便起见,可以反转所有条目-这可以通过使用索引来绕过
entries.forEach(entry=>entry.reverse());
进位=0;
对于(设idx=0;idx条目[idx]| | 0)
.减少((acc,值)=>acc+值,进位);
常数1=总和%10;
进位=数学下限(总和/10);
回答:取消移位(个);
log({message:“summation”,sum,one,carry,answer});
}
//加上最后的总和进位
//记住,我们以前倒过,倒过
//回答:反向()
addCarry(进位,应答);
//定案
const result=answer.join(“”);
const expected=(parseInt(lhs)*parseInt(rhs)).toString();//由于某种原因字符串
log({message:“finish”,expr:`${lhs}*${rhs}=${answer.join(“”)}`,answer,应为});

这个问题比前面提到的要复杂得多

假设实际的“长乘法”模拟,即只允许数字乘法和求和,请参见下面的注释和工作代码

首先,代码忽略了两个数字的乘法将溢出并产生一个非零进位值的事实,该进位值应与下一次乘法相加

第二,正如我们在学校里所说的,对于每一个数字,我们都会收到一个新的乘法结果和第二个数的所有其他数字。我们最终需要对这些乘法结果求和

下面的代码适用于非负十进制数。它可以被简化,但它试图保持初始算法的精神

// parameters
const lhs = "445";
const rhs = "456";

// utilities
const createZeros = length => new Array(length).fill(0);
const padArrayEnd = (length, padding, array) => [...array, ...createZeros(length - array.length)];
const last = array => array[array.length - 1];

// given a carray and an array of digits, add the carry to the last digit.
// if the result overflows, add the remainder as a new digit instead
// example;
//   array = [3, 4, 5]; addCarry(2, array); array == [3, 4, 7]
//   array = [3, 4, 9]; addCarry(2, array); array == [3, 4, 0, 1]
function addCarry(carry, digits) {
    if (carry == 0) {
        return;
    }

    let value = last(digits) + carry;
    if (value > 10) {
        digits[digits.length - 1] = 0;
        digits.unshift(value % 10);
    } else {
        digits[digits.length - 1] = value;
    }
}

console.log({ message: "start", lhs, rhs });

// state
const answer = [];
const entries = [];
let carry = 0;

// perform digit by digit multiplication.
// remember that the result array for each digit should have N leading zeros, where N is the position of that digit.
// this is the reason we keep an array of entries. each entry, is the result array corresponding to that digit
for(let lcur = 0; lcur < lhs.length; lcur++) {
    const leftDigit = lhs[lhs.length - 1 - lcur];

    // the multiplications entry
    const multiplications = createZeros(lcur);

    for(let rcur = 0; rcur < rhs.length; rcur++) {
        const rightDigit = rhs[rhs.length - 1 - rcur];

        // perform multiplication, but notice that in case of overflow we keep
        // only the ones, and remember carry for next iteration
        const times = (leftDigit * rightDigit) + carry;
        const ones = times % 10;
        carry = Math.floor(times / 10);

        multiplications.unshift(ones);
        console.log({ message: "step", expr: `${leftDigit} * ${rightDigit}`, times, ones, carry });
    }

    if (carry != 0){
        multiplications.unshift(carry);
        carry = 0;
    }

    // update entries
    entries.push(multiplications); 
    console.log({ message: "entry", multiplications });
}

// add the final carry
addCarry(carry, last(entries));

console.log({ message: "entries", entries });

// sum all entries with carries
const maxLength = entries
    .map(entry => entry.length)
    .reduce((acc, entry) => Math.max(acc, entry), 0);

// for convinience, reverse all entries - this can by bypassed with messing around with indices
entries.forEach(entry => entry.reverse());

carry = 0;
for (let idx = 0; idx < maxLength; ++idx) {
    const sum = entries
        .map(entry => entry[idx] || 0)
        .reduce((acc, value) => acc + value, carry);

    const ones = sum % 10;
    carry = Math.floor(sum / 10);

    answer.unshift(ones);
    console.log({ message: "summation", sum, ones, carry, answer });
}

// add final summation carry
// remember that we reversed stuff before, reverse back
// answer.reverse()
addCarry(carry, answer);

// finalize a result 
const result = answer.join("");
const expected = (parseInt(lhs) * parseInt(rhs)).toString(); // string for some reason
console.log({ message: "finish", expr: `${lhs} * ${rhs} = ${answer.join("")}`, answer, expected });
//参数
const lhs=“445”;
const rhs=“456”;
//公用事业
const createZeros=length=>新数组(长度).fill(0);
常量padarayend=(长度、填充、数组)=>[…数组,…创建零(长度-数组.length)];
const last=array=>array[array.length-1];
//给定一个进位和一个数字数组,将进位添加到最后一个数字。
//如果结果溢出,则将余数添加为新数字
//榜样;
//数组=[3,4,5];addCarry(2,array);数组==[3,4,7]
//数组=[3,4,9];addCarry(2,数组);数组==[3,4,0,1]
函数addCarry(进位,数字){
如果(进位==0){
返回;
}
让值=最后(位数)+进位;
如果(值>10){
位数[位数.长度-1]=0;
数字。取消移位(值%10);
}否则