# 数字计算

关于浮点数的存储和计算,会丢失精度这个事情就不说了, 这块需要去了解计算机是怎么存储浮点数,以及为什么会产生这个精度问题的,我们就讨论一下我们js里面常遇到的问题,以及一些解决办法即可。

比如我们经常做加法遇到, 非常常见的一个问题

0.1 + 0.2 => 0.30000000000000004

我们现在就是要解决如何正确的获取到0.3这个结果即可。 实用为主。具体的办法还真得去好好看看,这个文章就提供2个三方库解决这个问题。

# 1、number-precision

一个是比较轻量级的number-precision (opens new window)

const NP = require('number-precision');
NP.strip(0.09999999999999998); // = 0.1
NP.plus(0.1, 0.2); // = 0.3, not 0.30000000000000004
NP.plus(2.3, 2.4); // = 4.7, not 4.699999999999999
NP.minus(1.0, 0.9); // = 0.1, not 0.09999999999999998
NP.times(3, 0.3); // = 0.9, not 0.8999999999999999
NP.times(0.362, 100); // = 36.2, not 36.199999999999996
NP.divide(1.21, 1.1); // = 1.1, not 1.0999999999999999
NP.round(0.105, 2); // 0.11

保证一般简单的加减乘除没问题。

# 2、BigNumber

接下来学习下BigNumber (opens new window),他的API特别多, 我们可以先学会最基础的加减乘除

# 加减乘除幂

const x = BigNumber(0.1);
const y = BigNumber(0.2);
// 加法
console.log(x.plus(y).toString());
console.log(x.plus(y).toNumber());

const z = BigNumber(0.3);
// 减法
console.log(z.minus(0.1).toNumber()); // 0.2
// 乘法
console.log(z.times(y).toNumber()); // 0.06
// 除法
console.log(z.div(y).toNumber()); // 1.5
// 指数
const x1 = new BigNumber(0.7)
console.log(x1.pow(2).toNumber()); // 0.49

# 四舍五入取整操作

rm value desc desc-cn
ROUND_UP 0 Rounds away from zero 远离0取值, 也就是正数向上取整 负数向下取整
ROUND_DOWN 1 Rounds towards zero 趋向0取值, 也就是正数向下取整 负数向上取整
ROUND_CEIL 2 Rounds towards Infinity 向上取值
ROUND_FLOOR 3 Rounds towards -Infinity 向下取值
ROUND_HALF_UP 4 Rounds towards nearest neighbour. If equidistant, rounds away from zero 四舍五入取值, 如果等距就远离0
ROUND_HALF_DOWN 5 Rounds towards nearest neighbour. If equidistant, rounds towards zero 四舍五入取值, 如果等距就趋向0
ROUND_HALF_EVEN 6 Rounds towards nearest neighbour. If equidistant, rounds towards even neighbour 四舍五入取值, 如果等距就取偶数值
ROUND_HALF_CEIL 7 Rounds towards nearest neighbour. If equidistant, rounds towards Infinity 四舍五入取值,向下取值
ROUND_HALF_FLOOR 8 Rounds towards nearest neighbour. If equidistant, rounds towards -Infinity 四舍五入取值,向上取值
// 四舍五入取整
const BigNumber = require('bignumber.js');
BigNumber.config({ ROUNDING_MODE: 1 });
// ROUNDING_MODE

const x = new BigNumber(123.456);

// BigNumber.ROUND_CEIL 向上取整
console.log(x.integerValue(BigNumber.ROUND_CEIL).toNumber()); // 124
// BigNumber.ROUND_FLOOR 向下取整
console.log(x.integerValue(BigNumber.ROUND_FLOOR).toNumber()); // 123

// BigNumber.ROUND_UP 远离0取整, 也就是正数向上取整 负数向下取整
const a1 = BigNumber(10.4);
const a2 = BigNumber(-10.4);
console.log(a1.integerValue(BigNumber.ROUND_UP).toNumber()); // 11
console.log(a2.integerValue(BigNumber.ROUND_UP).toNumber()); // -11

// BigNumber.ROUND_DOWN 趋向0取整, 也就是正数向下取整 负数向上取整
const b1 = BigNumber(10.4);
const b2 = BigNumber(-10.4);
console.log(b1.integerValue(BigNumber.ROUND_DOWN).toNumber()); // 10
console.log(b2.integerValue(BigNumber.ROUND_DOWN).toNumber()); // -10

// BigNumber.ROUND_HALF_UP 就近取整, 如果等距就远离0
const c1 = BigNumber(10.3);
const c2 = BigNumber(-10.6);
console.log(c1.integerValue(BigNumber.ROUND_HALF_UP).toNumber()); // 10
console.log(c2.integerValue(BigNumber.ROUND_HALF_UP).toNumber()); // -11

// BigNumber.ROUND_HALF_DOWN 就近取整, 如果等距就趋于0
const d1 = BigNumber(10.3);
const d2 = BigNumber(-10.5);
console.log(d1.integerValue(BigNumber.ROUND_HALF_DOWN).toNumber()); // 10
console.log(d2.integerValue(BigNumber.ROUND_HALF_DOWN).toNumber()); // -10

// BigNumber.ROUND_HALF_EVEN 就近取整, 如果等距就取偶数整
console.log(BigNumber(10.5).integerValue(BigNumber.ROUND_HALF_EVEN).toNumber()); // 10
console.log(BigNumber(-11.5).integerValue(BigNumber.ROUND_HALF_EVEN).toNumber()); // -12

// BigNumber.ROUND_HALF_CEIL 就近取整, 如果等距向上取整
// BigNumber.ROUND_HALF_DOWN 就近取整, 如果等距向下取整
# 其他实用操作
// 绝对值
const v = new BigNumber(-0.8);
console.log(v.abs().toNumber()); // 0.8

// 比较
const v1 = new BigNumber(1);
const v2 = new BigNumber(2);
console.log(v1.comparedTo(v2)); // comparedTo 可以理解为 >=, v1 >= v2, 大于返回1 小于返回-1 等于返回0

// 判断相等
const v3 = BigNumber(0.3);
const v4 = BigNumber(0.3);
console.log(v3.isEqualTo(0.3)); // true
console.log(v3.isEqualTo(v3)); // true
console.log(v3.isEqualTo(v4)); // true

// 判断大于
console.log(BigNumber(0.3).gt(BigNumber(0.2))); // true
console.log(BigNumber(0.2).gt(BigNumber(0.2))); // false

// 大于等于
console.log(BigNumber(0.3).gte(BigNumber(0.2))); // true
console.log(BigNumber(0.2).gte(BigNumber(0.2))); // true

// 小于 小于等于  lt  lte

// 开方运算
console.log(Math.sqrt(0.04));
console.log(BigNumber(0.04).sqrt().toNumber()); // 0.2
# 数字显示API
// toExponential 输出指数形式
console.log(BigNumber('1000003131230000').toExponential()); // 1.00000313123e+15

// toString 在一定范围内输出数字形式,超出返回指数形式
console.log(BigNumber('1000003131230000').toString()); //1000003131230000
console.log(BigNumber('100000313123000000000000000').toString()); //1.00000313123e+26

// toFixed 总是输出数字形式
console.log(BigNumber('100000313123000000000000000').toFixed()); // 100000313123000000000000000
// 保留小数位数, HALF
console.log(BigNumber('123.456').toFixed(2, BigNumber.ROUND_FLOOR)); // 123.45
console.log(BigNumber('123.451').toFixed(2, BigNumber.ROUND_CEIL)); // 123.46
console.log(BigNumber('123.451').toFixed(2, BigNumber.ROUND_HALF_DOWN)); // 123.45
console.log(BigNumber('123.455').toFixed(2, BigNumber.ROUND_HALF_UP)); // 123.46

// toFormat 格式化
console.log(BigNumber('100000313123000000000000000').toFormat(3)); // 100,000,313,123,000,000,000,000,000.000

// toNumber
console.log(BigNumber(0.1).plus(0.2).toNumber()); // 数字 0.3, 不是字符串

个人觉得 BigNumber 在处理一般的业务时, 足够使用了。毕竟实用为主么

# 3、轻量化简易加减乘除, 会丢失精度

一个比较简单的加减乘除,能满足一般的要求,参数最好传入字符串,应该都是字符串的一些操作。 但是肯定还有一些问题的,比如参数传入0.00000001,toString之后就变成了'1e-8'的科学计数形式,

function mul(a, b) {
  let c = 0,
    d = a.toString(),
    e = b.toString();
  try {
    c += d.split('.')[1].length;
  } catch (f) {}
  try {
    c += e.split('.')[1].length;
  } catch (f) {}
  return (Number(d.replace('.', '')) * Number(e.replace('.', ''))) / Math.pow(10, c);
}

function add(a, b) {
  let c, d, e;
  try {
    c = a.toString().split('.')[1].length;
  } catch (f) {
    c = 0;
  }
  try {
    d = b.toString().split('.')[1].length;
  } catch (f) {
    d = 0;
  }
  e = Math.pow(10, Math.max(c, d));
  return (mul(a, e) + mul(b, e)) / e;
}

function sub(a, b) {
  let c, d, e;
  try {
    c = a.toString().split('.')[1].length;
  } catch (f) {
    c = 0;
  }
  try {
    d = b.toString().split('.')[1].length;
  } catch (f) {
    d = 0;
  }
  e = Math.pow(10, Math.max(c, d));
  return (mul(a, e) - mul(b, e)) / e;
}

function divide(a, b) {
  var c,
    d,
    e = 0,
    f = 0;
  try {
    e = a.toString().split('.')[1].length;
  } catch (g) {
    e = 0;
  }
  try {
    f = b.toString().split('.')[1].length;
  } catch (g) {
    f = 0;
  }
  c = Number(a.toString().replace('.', ''));
  d = Number(b.toString().replace('.', ''));
  return mul(c / d, Math.pow(10, f - e));
}

// 四舍五入保留小数位数
function round(num, precision) {
  const base = Math.pow(10, precision);
  return (Math.round((num.toPrecision(17) * base).toFixed(1)) / base).toFixed(precision);
}

// 截位小数部分 intercept(0.1365, 2) => '0.13', 不进行4舍五入操作
function intercept(num, len) {
  let a, b;
  try {
    const c = num.toString().split('.');
    a = c[0] || '';
    b = c[1] || '';
  } catch (error) {
    a = '';
    b = '';
  }
  b = b.substring(0, len);
  return toNonExponential([a, b].filter(Boolean).join('.'));
}

/**
 * 把一个数字转换为非科学计数显示的字符串
 * 超出精度的还是有问题的
 * @param {string | number} num
 * @return {string}
 */
function toNonExponential(num) {
  if (typeof num === 'string') {
    num = num - 0;
  }
  var m = num.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/);
  return num.toFixed(Math.max(0, (m[1] || '').length - m[2]));
}

/**
 * 列表求和
 *
 * @param {Array<number | string>} [args=[]]
 * @return {string}
 */
function sum(...args) {
  console.log(args);
  args = [...args].filter(num => {
    if (typeof num === 'string') {
      num = num.trim();
    }
    return Boolean(num);
  });
  let _sumVal = args.reduce((prev, cur) => {
    return add(prev, cur);
  }, 0);
  return toNonExponential(_sumVal);
}

// console.log(sum(...[1, 2, 3, 4, 0.1, 0.2, '', 0, false, ' ']));

export { mul, add, sub, divide, round, intercept, sum, toNonExponential };

# 4、字符串的加减乘除。除法可以丢失精度

    class LightBigNumber {
      constructor(value) {
        this.value = String(value).trim() || '0';
      }

      add(other) {
        return new LightBigNumber(addStrings(this.value, String(other)));
      }

      sub(other) {
        return new LightBigNumber(subStrings(this.value, String(other)));
      }

      mul(other) {
        return new LightBigNumber(mulStrings(this.value, String(other)));
      }

      div(other, precision = 10) {
        return new LightBigNumber(divStrings(this.value, String(other), precision));
      }

      toString() {
        return this.value;
      }

      toNumber() {
        return Number(this.value);
      }
    }

    // 字符串加法(精确)
    function addStrings(a, b) {
      // 处理负数
      if (a.startsWith('-') && b.startsWith('-')) return '-' + addStrings(a.slice(1), b.slice(1));
      if (a.startsWith('-')) return subStrings(b, a.slice(1));
      if (b.startsWith('-')) return subStrings(a, b.slice(1));

      // 转换为字符串
      const strA = a.toString();
      const strB = b.toString();

      const [intA, decA = ''] = strA.split('.');
      const [intB, decB = ''] = strB.split('.');
      const maxDec = Math.max(decA.length, decB.length);

      let carry = 0;
      let result = '';

      // 小数部分
      for (let i = maxDec - 1; i >= 0; i--) {
        const sum = Number(decA[i] || 0) + Number(decB[i] || 0) + carry;
        result = (sum % 10) + result;
        carry = Math.floor(sum / 10);
      }

      // 整数部分
      let i = intA.length - 1,
        j = intB.length - 1;
      while (i >= 0 || j >= 0 || carry) {
        const sum = Number(intA[i] || 0) + Number(intB[j] || 0) + carry;
        result = (sum % 10) + result;
        carry = Math.floor(sum / 10);
        i--;
        j--;
      }

      let _result = ''
      // 处理小数点和前导零
      if (maxDec > 0) {
        // 确保整数部分不为空
        const integerPart = result.length > maxDec ? result.slice(0, -maxDec) : '0';
        const decimalPart = result.slice(-maxDec);

        // 去掉小数部分尾部的零
        const trimmedDecimal = decimalPart.replace(/0+$/, '');

        if (trimmedDecimal) {
          _result = integerPart + '.' + trimmedDecimal;
        } else {
          _result = integerPart;
        }
      } else {
        // 没有小数部分,去掉前导零
        _result = result.replace(/^0+/, '') || '0';
      }

      if (_result == '-0') {
        _result = '0'
      }

      return _result
    }


    // 字符串乘法(精确)
    function mulStrings(a, b) {
      let sign = '';
      if ((a.startsWith('-') && !b.startsWith('-')) || (!a.startsWith('-') && b.startsWith('-')))
        sign = '-';
      a = a.replace(/^-/, '');
      b = b.replace(/^-/, '');

      const decA = a.split('.')[1] || '';
      const decB = b.split('.')[1] || '';
      const totalDecimals = decA.length + decB.length;

      const intA = a.replace('.', '');
      const intB = b.replace('.', '');

      const result = Array(intA.length + intB.length).fill(0);

      for (let i = intA.length - 1; i >= 0; i--) {
        for (let j = intB.length - 1; j >= 0; j--) {
          const mul = Number(intA[i]) * Number(intB[j]) + result[i + j + 1];
          result[i + j + 1] = mul % 10;
          result[i + j] += Math.floor(mul / 10);
        }
      }

      let str = result.join('').replace(/^0+/, '') || '0';

      if (totalDecimals > 0) {
        if (str.length <= totalDecimals) {
          str = '0'.repeat(totalDecimals - str.length + 1) + str;
        }
        str = str.slice(0, -totalDecimals) + '.' + str.slice(-totalDecimals);
        str = str.replace(/\.?0+$/, '');
      }

      return sign + str;
    }

    // 字符串除法(支持精度控制,四舍五入)
    function divStrings(a, b, precision = 10) {
      let sign = '';
      if ((a.startsWith('-') && !b.startsWith('-')) || (!a.startsWith('-') && b.startsWith('-')))
        sign = '-';
      a = a.replace(/^-/, '');
      b = b.replace(/^-/, '');

      if (b === '0') return 'NaN';
      if (a === '0') return '0';

      // 标准化为整数
      const [intA, decA = ''] = a.split('.');
      const [intB, decB = ''] = b.split('.');

      const decDiff = decA.length - decB.length;
      let dividend = intA + decA;
      let divisor = intB + decB;

      if (decDiff < 0) dividend += '0'.repeat(-decDiff);
      if (decDiff > 0) divisor += '0'.repeat(decDiff);

      dividend = dividend.replace(/^0+/, '') || '0';
      divisor = divisor.replace(/^0+/, '') || '0';

      // 长除法
      let quotient = '';
      let remainder = '';
      let idx = 0;
      let current = '';

      while (idx < dividend.length && compare(current, divisor) < 0) {
        current += dividend[idx++];
      }

      if (compare(current, divisor) < 0) {
        quotient = '0';
        remainder = current;
      } else {
        while (idx <= dividend.length) {
          let digit = 0;
          for (let d = 9; d >= 0; d--) {
            if (compare(mulStrings(divisor, String(d)), current) <= 0) {
              digit = d;
              break;
            }
          }
          quotient += digit;
          remainder = subStrings(current, mulStrings(divisor, String(digit)));
          if (idx < dividend.length) remainder += dividend[idx];
          idx++;
          current = remainder;
        }
      }

      // 小数部分
      let decimalPart = '';
      if (precision > 0) {
        let decRemainder = remainder;
        for (let i = 0; i < precision + 1; i++) {
          if (decRemainder === '0') break;
          decRemainder += '0';
          let digit = 0;
          for (let d = 9; d >= 0; d--) {
            if (compare(mulStrings(divisor, String(d)), decRemainder) <= 0) {
              digit = d;
              break;
            }
          }
          decimalPart += digit;
          decRemainder = subStrings(decRemainder, mulStrings(divisor, String(digit)));
        }

        // 四舍五入
        if (decimalPart.length > precision) {
          const lastDigit = Number(decimalPart[precision]);
          decimalPart = decimalPart.slice(0, precision);
          if (lastDigit >= 5) {
            let decNum = Number(decimalPart) + 1;
            if (decNum.toString().length > precision) {
              quotient = addStrings(quotient, '1');
              decimalPart = decNum.toString().slice(1);
            } else {
              decimalPart = decNum.toString().padStart(precision, '0');
            }
          }
        }
      }

      let result = quotient + (decimalPart ? '.' + decimalPart : '');
      result = result.replace(/^0+\./, '0.').replace(/\.0+$/, '');
      if (result.startsWith('0.') && result.length > 2) {
        result = result.replace(/^0+/, '');
      }

      if (result.indexOf('.') === 0) {
        result = '0' + result
      }

      return sign + result;
    }

    // 比较两个正整数字符串
    // function compare(a, b) {
    //   a = a.replace(/^0+/, '');
    //   b = b.replace(/^0+/, '');
    //   if (a.length > b.length) return 1;
    //   if (a.length < b.length) return -1;
    //   return a.localeCompare(b);
    // }

    // 字符串减法(精确) - 修复版
    function subStringsReal(a, b) {
      if (a.startsWith('-') && b.startsWith('-')) return subStrings(b.slice(1), a.slice(1));
      if (a.startsWith('-')) return '-' + addStrings(a.slice(1), b);
      if (b.startsWith('-')) return addStrings(a, b.slice(1));

      if (compare(a, b) < 0) return '-' + subStrings(b, a);

      const [intA, decA = ''] = a.split('.');
      const [intB, decB = ''] = b.split('.');
      const maxDec = Math.max(decA.length, decB.length);

      let borrow = 0;
      let result = '';

      // 小数部分
      for (let i = maxDec - 1; i >= 0; i--) {
        let diff = Number(decA[i] || 0) - Number(decB[i] || 0) - borrow;
        if (diff < 0) {
          diff += 10;
          borrow = 1;
        } else {
          borrow = 0;
        }
        result = diff + result;
      }

      // 整数部分
      let i = intA.length - 1,
        j = intB.length - 1;
      while (i >= 0 || j >= 0 || borrow) {
        let diff = Number(intA[i] || 0) - Number(intB[j] || 0) - borrow;
        if (diff < 0) {
          diff += 10;
          borrow = 1;
        } else {
          borrow = 0;
        }
        result = diff + result;
        i--;
        j--;
      }

      // 修复:正确处理整数部分和小数部分
      let integerPart, decimalPart;
      let _result = ''
      if (maxDec > 0) {
        // 分离整数部分和小数部分
        const intLen = result.length - maxDec;
        if (intLen > 0) {
          integerPart = result.slice(0, intLen);
          decimalPart = result.slice(intLen);
        } else {
          integerPart = '0';
          // 前面补0到maxDec位
          decimalPart = result.padStart(maxDec, '0');
        }

        // 去掉整数部分的前导零(但至少保留一个0)
        integerPart = integerPart.replace(/^0+/, '') || '0';

        // 去掉小数部分尾部的零
        decimalPart = decimalPart.replace(/0+$/, '');


        // 组合结果
        if (decimalPart) {
          _result = integerPart + '.' + decimalPart;
        } else {
          _result = integerPart;
        }
      } else {
        // 没有小数部分,直接处理整数
        _result = result.replace(/^0+/, '') || '0';
      }
      if (_result == '-0') {
        _result = 0
      }
      return _result;
    }

    function subStrings(a, b) {
      let ret = subStringsReal(a, b);
      if (ret === '-0') {
        ret = '0'
      }
      return ret;
    }
    // 比较两个数字字符串的大小(辅助函数)
    function compare(a, b) {
      // 处理负数
      if (a.startsWith('-') && b.startsWith('-')) return compare(b.slice(1), a.slice(1));
      if (a.startsWith('-')) return -1;
      if (b.startsWith('-')) return 1;

      // 移除前导零
      a = a.replace(/^0+/, '') || '0';
      b = b.replace(/^0+/, '') || '0';

      const [intA, decA = ''] = a.split('.');
      const [intB, decB = ''] = b.split('.');

      // 比较整数部分
      if (intA.length !== intB.length) {
        return intA.length > intB.length ? 1 : -1;
      }
      if (intA !== intB) {
        return intA > intB ? 1 : -1;
      }

      // 比较小数部分
      const maxDec = Math.max(decA.length, decB.length);
      const decAPadded = decA.padEnd(maxDec, '0');
      const decBPadded = decB.padEnd(maxDec, '0');

      if (decAPadded !== decBPadded) {
        return decAPadded > decBPadded ? 1 : -1;
      }

      return 0;
    }



    export {
      LightBigNumber,
      addStrings,
      subStrings,
      mulStrings,
      divStrings,
      compare
    };

使用示例

    // 使用示例
    const n1 = new LightBigNumber('0.1');
    console.log(n1.add('0.2').toString()); // "0.3"
    console.log(n1.mul('0.1').toString()); // "0.01"
    console.log(n1.div('3').toString()); // "0.03333333333333333"

    const n2 = new LightBigNumber('12345678901234567890.123456789');
    console.log(n2.add('1').toString()); // "12345678901234567891.123456789"
    console.log(n2.mul('2').toString()); // "24691357802469135780.246913578"

    const n3 = new LightBigNumber('9007199254740992')
    console.log(n3.add('7').toString());
    console.log(addStrings('9007199254740992', '9007199254743453412312312312312353534534535353450992'));

    console.log(mulStrings('9007199254740992', '9007199254740992'));

单元测试用例


    const subtest = () => {
      const testCases = [
        // 基础整数减法
        {
          a: "0.1",
          b: "0.1",
          expected: "0"
        },
        {
          a: "0.1",
          b: "-0.1",
          expected: "0.2"
        },
        {
          a: "-0.1",
          b: "0.1",
          expected: "-0.2"
        },
        {
          a: "0.1",
          b: "0.05",
          expected: "0.05"
        },
        {
          a: "0.1",
          b: "0.005",
          expected: "0.095"
        },
        {
          a: "100",
          b: "30",
          expected: "70"
        },
        {
          a: "200",
          b: "300",
          expected: "-100"
        },
        {
          a: "0",
          b: "0",
          expected: "0"
        },

        // 大数减法(超出Number精度)
        {
          a: "12345678901234567890",
          b: "1",
          expected: "12345678901234567889"
        },
        {
          a: "99999999999999999999",
          b: "100000000000000000000",
          expected: "-1"
        },

        // 浮点数减法
        {
          a: "3.14",
          b: "1.0",
          expected: "2.14"
        },
        {
          a: "0.1",
          b: "0.2",
          expected: "-0.1"
        },
        {
          a: "100.00",
          b: "0.01",
          expected: "99.99"
        },

        // 负数减法
        {
          a: "-50",
          b: "30",
          expected: "-80"
        },
        {
          a: "-50",
          b: "-30",
          expected: "-20"
        },
        {
          a: "10",
          b: "-5",
          expected: "15"
        },
        {
          a: "-10",
          b: "-5",
          expected: "-5"
        },

        // 前导零
        {
          a: "00100",
          b: "00001",
          expected: "99"
        },
        {
          a: "000.100",
          b: "0.01",
          expected: "0.09"
        },
        {
          a: "0000",
          b: "0000",
          expected: "0"
        },

        // 边界情况
        {
          a: "0",
          b: "1",
          expected: "-1"
        },
        {
          a: "1",
          b: "0",
          expected: "1"
        },
        {
          a: "999999999999999999999999",
          b: "999999999999999999999999",
          expected: "0"
        },
        {
          a: "123.456",
          b: "123.456",
          expected: "0"
        },

        // 高精度减法
        {
          a: "123.456789012345678900",
          b: "0.000000000123456789",
          expected: "123.456789012222222111"
        },

        // 空格处理
        {
          a: "123",
          b: "45",
          expected: "78"
        },



        {
          a: "0",
          b: "123",
          expected: "-123"
        },
        {
          a: "123",
          b: "0",
          expected: "123"
        },
        {
          a: "0",
          b: "0",
          expected: "0"
        },
        {
          a: "0.00",
          b: "0",
          expected: "0"
        },
      ];


      function runTests(testFunc) {
        console.log("开始测试数字字符串减法...\n");

        let passed = 0;
        let failed = 0;

        testCases.forEach((testCase, index) => {
          const {
            a,
            b,
            expected
          } = testCase;
          const result = testFunc(a, b);

          const success = result === expected;

          if (success) {
            passed++;
            console.log(`✅ 测试 ${index + 1} 通过: subStrings("${a}", "${b}") = "${result}"`);
          } else {
            failed++;
            console.log(`❌ 测试 ${index + 1} 失败: subStrings("${a}", "${b}")`);
            console.log(`   期望: "${expected}"`);
            console.log(`   实际: "${result}"`);
          }
        });

        console.log(`\n测试结果: ${passed} 通过, ${failed} 失败`);
        console.log(`通过率: ${(passed / testCases.length * 100).toFixed(1)}%`);

        return {
          passed,
          failed
        };
      }

      // 执行测试
      runTests(subStrings);
    }
    subtest();


    const mulTest = () => {
      const testCases = [
        // 1. 基本整数乘法
        {
          name: "基本整数乘法",
          input: ["2", "3"],
          expected: "6"
        },
        {
          name: "多位数整数乘法",
          input: ["12", "12"],
          expected: "144"
        },
        {
          name: "大整数乘法",
          input: ["123456789", "987654321"],
          expected: "121932631112635269"
        },

        // 2. 零的乘法
        {
          name: "零乘以任何数",
          input: ["0", "12345"],
          expected: "0"
        },
        {
          name: "任何数乘以零",
          input: ["999", "0"],
          expected: "0"
        },

        // 3. 1的乘法
        {
          name: "乘以1",
          input: ["123", "1"],
          expected: "123"
        },
        {
          name: "1乘以任何数",
          input: ["1", "999999999999"],
          expected: "999999999999"
        },

        // 4. 负数乘法
        {
          name: "正数乘负数",
          input: ["5", "-3"],
          expected: "-15"
        },
        {
          name: "负数乘正数",
          input: ["-7", "4"],
          expected: "-28"
        },
        {
          name: "负数乘负数",
          input: ["-6", "-9"],
          expected: "54"
        },

        // 5. 浮点数乘法
        {
          name: "浮点数相乘",
          input: ["2.5", "4"],
          expected: "10"
        },
        {
          name: "两个浮点数相乘",
          input: ["1.5", "2.5"],
          expected: "3.75"
        },
        {
          name: "小数点后多位数相乘",
          input: ["0.123", "0.456"],
          expected: "0.056088"
        },

        // 6. 特殊精度测试
        {
          name: "避免浮点精度问题",
          input: ["0.1", "0.2"],
          expected: "0.02" // 注意:直接计算可能得到 0.020000000000000004
        },
        {
          name: "π的近似值相乘",
          input: ["3.14159", "2"],
          expected: "6.28318"
        },

        // 7. 大数乘法(超出普通整数范围)
        {
          name: "超大整数相乘",
          input: ["123456789012345678901234567890", "98765432109876543210987654321"],
          // expected: "12193263111263526901263526901219326311126352690126352690"
          expected: "12193263113702179522618503273362292333223746380111126352690"
        },



        // 9. 边缘情况
        {
          name: "乘数为1位数",
          input: ["9", "9"],
          expected: "81"
        },
        {
          name: "一个数为0,另一个为大数",
          input: ["0", "123456789012345678901234567890"],
          expected: "0"
        },
        {
          name: "乘法结果为零但中间有进位",
          input: ["100", "0.01"],
          expected: "1"
        },

        // 10. 性能测试用例
        {
          name: "大数乘法性能测试1",
          input: ["999999999999999999999999999999", "2"],
          expected: "1999999999999999999999999999998"
        },
        {
          name: "大数乘法性能测试2",
          input: ["123456789012345678901234567890", "123456789012345678901234567890"],
          // expected: "12193263113702179522618503273362292333223746380111126352690"
          expected: "15241578753238836750495351562536198787501905199875019052100"
        }
      ];

      // 测试函数示例
      function runTests(multiplyFunction) {
        console.log("开始执行字符串乘法测试...\n");

        let passed = 0;
        let failed = 0;

        testCases.forEach((testCase, index) => {
          const [a, b] = testCase.input;
          const expected = testCase.expected;

          try {
            const result = multiplyFunction(a, b);
            const isPass = result === expected;

            if (isPass) {
              console.log(`✅ 测试 ${index + 1}: ${testCase.name}`);
              console.log(`   输入: "${a}" × "${b}"`);
              console.log(`   结果: "${result}"`);
              console.log(`   状态: 通过\n`);
              passed++;
            } else {
              console.log(`❌ 测试 ${index + 1}: ${testCase.name}`);
              console.log(`   输入: "${a}" × "${b}"`);
              console.log(`   期望: "${expected}"`);
              console.log(`   实际: "${result}"`);
              console.log(`   状态: 失败\n`);
              failed++;
            }
          } catch (error) {
            console.log(`💥 测试 ${index + 1}: ${testCase.name}`);
            console.log(`   输入: "${a}" × "${b}"`);
            console.log(`   错误: ${error.message}`);
            console.log(`   状态: 抛出异常\n`);
            failed++;
          }
        });

        console.log(`\n测试总结: ${testCases.length} 个测试用例`);
        console.log(`通过: ${passed}`);
        console.log(`失败: ${failed}`);
        console.log(`通过率: ${(passed / testCases.length * 100).toFixed(2)}%`);
      }

      // 如果您有具体的乘法函数,可以替换这里
      // function multiplyStrings(a, b) {
      //     // 您的乘法实现
      // }

      // 运行测试
      runTests(mulStrings);

    }
    mulTest()

    const addTest = () => {
      const testCases = [
        // 1. 基本整数加法
        {
          name: "基本整数加法",
          input: ["0", "0"],
          expected: "0"
        },
        {
          name: "基本整数加法",
          input: ["0.00", "0"],
          expected: "0"
        },
        {
          name: "基本整数加法",
          input: ["0.00", "0.01"],
          expected: "0.01"
        },
        {
          name: "基本整数加法",
          input: ["2", "3"],
          expected: "5"
        },
        {
          name: "多位数整数加法",
          input: ["12", "12"],
          expected: "24"
        },
        {
          name: "大整数加法",
          input: ["123456789", "987654321"],
          expected: "1111111110"
        },

        // 2. 零的加法
        {
          name: "零加任何数",
          input: ["0", "12345"],
          expected: "12345"
        },
        {
          name: "任何数加零",
          input: ["999", "0"],
          expected: "999"
        },
        {
          name: "零加零",
          input: ["0", "0"],
          expected: "0"
        },

        // 3. 1的加法
        {
          name: "加1",
          input: ["123", "1"],
          expected: "124"
        },
        {
          name: "1加任何数",
          input: ["1", "999999999999"],
          expected: "1000000000000"
        },

        // 4. 负数加法
        {
          name: "正数加负数(结果为正)",
          input: ["10", "-3"],
          expected: "7"
        },
        {
          name: "正数加负数(结果为负)",
          input: ["3", "-10"],
          expected: "-7"
        },
        {
          name: "负数加负数",
          input: ["-5", "-3"],
          expected: "-8"
        },
        {
          name: "负数加正数",
          input: ["-7", "4"],
          expected: "-3"
        },

        // 5. 浮点数加法
        {
          name: "浮点数相加",
          input: ["2.5", "1.5"],
          expected: "4"
        },
        {
          name: "两个浮点数相加",
          input: ["1.5", "2.5"],
          expected: "4"
        },
        {
          name: "小数点后多位数相加",
          input: ["0.123", "0.456"],
          expected: "0.579"
        },
        {
          name: "不同小数位数相加",
          input: ["1.2345", "0.67"],
          expected: "1.9045"
        },

        // 6. 特殊精度测试
        {
          name: "避免浮点精度问题1",
          input: ["0.1", "0.2"],
          expected: "0.3" // 注意:直接计算可能得到 0.30000000000000004
        },
        {
          name: "避免浮点精度问题2",
          input: ["0.7", "0.1"],
          expected: "0.8" // 注意:直接计算可能得到 0.7999999999999999
        },
        {
          name: "避免浮点精度问题3",
          input: ["0.3", "0.6"],
          expected: "0.9" // 注意:直接计算可能得到 0.8999999999999999
        },

        // 7. 大数加法(超出普通整数范围)
        {
          name: "超大整数相加1",
          input: ["123456789012345678901234567890", "98765432109876543210987654321"],
          // expected: "222222221111111111111111111211"
          expected: "222222221122222222112222222211"
        },
        {
          name: "超大整数相加2",
          input: ["999999999999999999999999999999", "1"],
          expected: "1000000000000000000000000000000"
        },



        // 9. 边缘情况
        {
          name: "加数为1位数",
          input: ["9", "9"],
          expected: "18"
        },
        {
          name: "一个数为0,另一个为大数",
          input: ["0", "123456789012345678901234567890"],
          expected: "123456789012345678901234567890"
        },
        {
          name: "加法结果有进位",
          input: ["99", "1"],
          expected: "100"
        },
        {
          name: "加法结果有连续进位",
          input: ["999", "1"],
          expected: "1000"
        },

        // 10. 性能测试用例
        {
          name: "大数加法性能测试1",
          input: ["999999999999999999999999999999", "1"],
          expected: "1000000000000000000000000000000"
        },
        {
          name: "大数加法性能测试2",
          input: ["123456789012345678901234567890", "123456789012345678901234567890"],
          expected: "246913578024691357802469135780"
        }
      ];

      // 测试函数示例
      function runTests(addFunction) {
        console.log("开始执行字符串加法测试...\n");

        let passed = 0;
        let failed = 0;

        testCases.forEach((testCase, index) => {
          const [a, b] = testCase.input;
          const expected = testCase.expected;

          try {
            const result = addFunction(a, b);
            const isPass = result === expected;

            if (isPass) {
              console.log(`✅ 测试 ${index + 1}: ${testCase.name}`);
              console.log(`   输入: "${a}" + "${b}"`);
              console.log(`   结果: "${result}"`);
              console.log(`   状态: 通过\n`);
              passed++;
            } else {
              console.log(`❌ 测试 ${index + 1}: ${testCase.name}`);
              console.log(`   输入: "${a}" + "${b}"`);
              console.log(`   期望: "${expected}"`);
              console.log(`   实际: "${result}"`);
              console.log(`   状态: 失败\n`);
              failed++;
            }
          } catch (error) {
            console.log(`💥 测试 ${index + 1}: ${testCase.name}`);
            console.log(`   输入: "${a}" + "${b}"`);
            console.log(`   错误: ${error.message}`);
            console.log(`   状态: 抛出异常\n`);
            failed++;
          }
        });

        console.log(`\n测试总结: ${testCases.length} 个测试用例`);
        console.log(`通过: ${passed}`);
        console.log(`失败: ${failed}`);
        console.log(`通过率: ${(passed / testCases.length * 100).toFixed(2)}%`);
      }

      // 如果您有具体的加法函数,可以替换这里
      // function addStrings(a, b) {
      //     // 您的加法实现
      // }

      // 运行测试
      runTests(addStrings);

    }
    addTest()

    const divTest = () => {
      // 测试函数示例
      function runTests(divideFunction) {
        const testCases = [{
            name: '基本整数除法(能整除)',
            input: ['0.1', '2'],
            expected: '0.05'
          },
          // 1. 基本整数除法(能整除)
          {
            name: '基本整数除法(能整除)',
            input: ['10', '2'],
            expected: '5'
          },
          {
            name: '多位数整数除法(能整除)',
            input: ['100', '25'],
            expected: '4'
          },
          {
            name: '大整数除法(能整除)',
            input: ['1234567890', '123456789'],
            expected: '10'
          },

          // 2. 整数除法(不能整除,需要小数)
          {
            name: '整数除法(不能整除)',
            input: ['10', '3'],
            expected: '3.3333333333' // 需要指定精度
          },
          {
            name: '整数除法(有小数部分)',
            input: ['7', '2'],
            expected: '3.5'
          },
          {
            name: '整数除法(多位小数)',
            input: ['1', '3'],
            expected: '0.3333333333'
          },

          // 3. 零的除法
          {
            name: '零除以任何数',
            input: ['0', '12345'],
            expected: '0'
          },
          {
            name: '任何数除以1',
            input: ['999', '1'],
            expected: '999'
          },
          {
            name: '任何数除以10的幂',
            input: ['12345', '10'],
            expected: '1234.5'
          },

          // 4. 负数除法
          {
            name: '正数除以负数',
            input: ['10', '-2'],
            expected: '-5'
          },
          {
            name: '负数除以正数',
            input: ['-10', '2'],
            expected: '-5'
          },
          {
            name: '负数除以负数',
            input: ['-10', '-2'],
            expected: '5'
          },
          {
            name: '负数除以负数(不能整除)',
            input: ['-7', '-3'],
            expected: '2.3333333333'
          },

          // 5. 浮点数除法
          {
            name: '浮点数除以整数',
            input: ['2.5', '2'],
            expected: '1.25'
          },
          {
            name: '整数除以浮点数',
            input: ['10', '2.5'],
            expected: '4'
          },
          {
            name: '两个浮点数相除',
            input: ['1.5', '2.5'],
            expected: '0.6'
          },
          {
            name: '小数点后多位数相除',
            input: ['0.123', '0.456'],
            expected: '0.26973684210526315789'
          },

          // 6. 特殊精度测试
          {
            name: '避免浮点精度问题1',
            input: ['0.1', '0.2'],
            expected: '0.5' // 注意:直接计算可能得到 0.49999999999999994
          },
          {
            name: '避免浮点精度问题2',
            input: ['0.7', '0.1'],
            expected: '7'
          },
          {
            name: '避免浮点精度问题3',
            input: ['0.3', '0.6'],
            expected: '0.5'
          },

          // 7. 大数除法(超出普通整数范围)
          {
            name: '超大整数相除1',
            input: ['123456789012345678901234567890', '2'],
            expected: '61728394506172839450617283945'
          },
          {
            name: '超大整数相除2',
            input: ['999999999999999999999999999999', '3'],
            expected: '333333333333333333333333333333'
          },
          {
            name: '超大整数相除3(不能整除)',
            input: ['123456789012345678901234567890', '7'],
            expected: '17636684144620811271604938270'
          },

          // 9. 边缘情况
          {
            name: '除数为1位数',
            input: ['9', '3'],
            expected: '3'
          },
          {
            name: '被除数为0,除数为大数',
            input: ['0', '123456789012345678901234567890'],
            expected: '0'
          },
          {
            name: '除法结果有小数部分',
            input: ['100', '0.01'],
            expected: '10000'
          },
          {
            name: '除法结果有连续小数',
            input: ['1', '3'],
            expected: '0.3333333333'
          },

          // 10. 性能测试用例
          {
            name: '大数除法性能测试1',
            input: ['999999999999999999999999999999', '3'],
            expected: '333333333333333333333333333333'
          },
          {
            name: '大数除法性能测试2',
            input: ['123456789012345678901234567890', '123456789012345678901234567890'],
            expected: '1'
          }
        ];

        console.log('开始执行字符串除法测试...\n');

        let passed = 0;
        let failed = 0;

        testCases.forEach((testCase, index) => {
          const [a, b] = testCase.input;
          const expected = testCase.expected;

          try {
            const result = divideFunction(a, b);
            const isPass = result === expected;

            if (isPass) {
              console.log(`✅ 测试 ${index + 1}: ${testCase.name}`);
              console.log(`   输入: "${a}" ÷ "${b}"`);
              console.log(`   结果: "${result}"`);
              console.log(`   状态: 通过\n`);
              passed++;
            } else {
              console.log(`❌ 测试 ${index + 1}: ${testCase.name}`);
              console.log(`   输入: "${a}" ÷ "${b}"`);
              console.log(`   期望: "${expected}"`);
              console.log(`   实际: "${result}"`);
              console.log(`   状态: 失败\n`);
              failed++;
            }
          } catch (error) {
            console.log(`💥 测试 ${index + 1}: ${testCase.name}`);
            console.log(`   输入: "${a}" ÷ "${b}"`);
            console.log(`   错误: ${error.message}`);
            console.log(`   状态: 抛出异常\n`);
            failed++;
          }
        });

        console.log(`\n测试总结: ${testCases.length} 个测试用例`);
        console.log(`通过: ${passed}`);
        console.log(`失败: ${failed}`);
        console.log(`通过率: ${((passed / testCases.length) * 100).toFixed(2)}%`);
      }

      // 如果您有具体的除法函数,可以替换这里
      // function divideStrings(a, b) {
      //     // 您的除法实现
      // }

      // 运行测试
      runTests(divStrings);
    };
    divTest()
上次更新: 4/1/2026, 5:23:57 AM