要求
- 输入两个string类型的值,均由0-9组成,最大长度为10000
- 求两个数之积
思路
- 按照乘法的步骤一步步来计算
- 即:个十百千...依次计算,最后给每组结果添加相应个数的0,然后把全部加起来
细节
- 竖式乘法计算步骤与两个数的长度有关,按照自己熟悉的顺序摆放位置
- 进位使用后要清零
- 内圈每一轮最后一次的进位不再是进位,直接保留在原数字上
- 外圈每轮开始时要清零进位
代码
function bigFlex(a, b) {
// 变成数组,然后翻转数组,方便从个位开始计算
a = a.split("").reverse();
b = b.split("").reverse();
let more = 0;
let result = [];
// 要注意,竖式乘法一般的计算步骤与两个数的长度有关,需要把长的放上面,短的放下面
let numa,
numb,
isLonger = false;
a.length > b.length ? (isLonger = false) : (isLonger = true);
if (isLonger) {
numa = a;
numb = b;
} else {
numa = b;
numb = a;
}
// 开始计算,外圈为较短的数,内圈为较长的数
numa.forEach((item, index) => {
more = 0; //每轮开始时进位要清零
result[index] = [];
numb.forEach((x, idx) => {
let r = "" + (x * item + more);
more = 0; //注意每次用完进位要清零
result[index].push(r[r.length - 1]);
if (r.length > 1) {
more = r[0] - 0;
}
if (idx + 1 == numb.length && more != 0) { //每轮最后一次的进位直接保留在开头,不再是进位
result[index].push("" + more);
}
});
});
let ret = 0;
result.forEach((item, index) => { //二维数组result每一项就是一轮计算的结果,依次添加相应数量的0
let num = item.reverse();
for (let i = 1; i <= index; i++) {
num.push("0");
}
ret += Number(num.join("")); //相加
});
return ret;
}
方法比较简单粗暴,循环比较多,但逻辑上比较简单
补充
-
上面方法有一个致命问题:使用竖式乘法最后会涉及每一轮相乘结果的相加,而相乘结果本身也非常大,可能超出正常加法计算的范围。
-
解决:新增大数加法
function bigAdd(a, b) {
a = a.split("").reverse();
b = b.split("").reverse();
// console.log(a, b); //***************************************************************** */
let result = [],
ret = [];
let more = 0;
let len = 0,
flag = "a";
if (a.length > b.length) {
len = b.length;
flag = "b";
} else {
len = a.length;
flag = "a";
}
// console.log(flag); //*************************************************************** */
// 循环,取较短的长度为循环次数
for (let i = 0; i < len; i++) {
let r = a[i] - 0 + (b[i] - 0) + more;
// console.log(r, "1r"); //********************************************* */
more = 0;
r = "" + r;
result.push(r[r.length - 1]);
if (r.length > 1) {
more = r[0] - 0;
}
}
// if (more != 0) {
if (flag == "a") {
for (let i = len; i < b.length; i++) {
// console.log(flag, more, b[i]);
if (more == 0) break;
let r = b[i] - 0 + more;
// console.log(r, "2r");
more = 0;
r = "" + r;
b[i] = r[r.length - 1];
if (r.length > 1) {
more = r[0] - 0;
}
}
ret = b.splice(len);
// b[len] = b[len] - 0 + more;
} else if (flag == "b") {
// a[len] = a[len] - 0 + more;
for (let i = len; i < a.length; i++) {
// console.log(flag, more, a[i], a.length);
if (more == 0) break;
let r = a[i] - 0 + more;
// console.log(r);
more = 0;
r = "" + r;
a[i] = r[r.length - 1];
if (r.length > 1) {
more = r[0] - 0;
}
}
ret = a.splice(len);
}
// }
// console.log(ret, 1);
if (more != 0) {
ret.push(more);
}
ret = result.concat(ret);
// console.log("return,,", ret);
return ret.reverse().join("");
}
- 修改乘法代码,将最后的相加改为使用大数加法解决
function bigFlex(a, b) {
// 变成数组,然后翻转数组,方便从个位开始计算
a = a.split("").reverse();
b = b.split("").reverse();
let more = 0;
let result = [];
// 要注意,竖式乘法一般的计算步骤与两个数的长度有关,需要把长的放上面,短的放下面
let numa,
numb,
isLonger = false;
a.length > b.length ? (isLonger = false) : (isLonger = true);
if (isLonger) {
numa = a;
numb = b;
} else {
numa = b;
numb = a;
}
// 开始计算,外圈为较短的数,内圈为较长的数
numa.forEach((item, index) => {
more = 0; //每轮开始时进位要清零
result[index] = [];
numb.forEach((x, idx) => {
let r = "" + (x * item + more);
more = 0; //注意每次用完进位要清零
result[index].push(r[r.length - 1]);
// console.log(r, more, result[index]);
if (r.length > 1) {
more = r[0] - 0;
}
if (idx + 1 == numb.length && more != 0) {
//每轮最后一次的进位直接保留在开头,不再是进位
result[index].push("" + more);
}
});
});
let ret = 0;
result.forEach((item, index) => {
//二维数组result每一项就是一轮计算的结果,依次添加相应数量的0
let num = item.reverse();
for (let i = 1; i <= index; i++) {
num.push("0");
}
// console.log(num.join(""));
// ret += Number(num.join("")); //相加
// console.log("add", ret, num.join(""));
ret = bigAdd("" + ret, num.join(""));
// console.log("ret", ret);
});
return ret;
}