混合精度算术:大整数尾数的大浮点除法算法?

Mixed precision arithmetic: Algorithm for big float division with big integer mantissa?

提问人:Kris B. 提问时间:4/24/2021 最后编辑:Kris B. 更新时间:4/25/2021 访问量:201

问:

我写了一个运行良好的 Big Integer 类。我想写一个大十进制类。我将类构建为以 10 为基数指数的浮点数,即以 M*10^e 的形式,其中 10^0 表示数字介于 [0.1, 1] 之间。

这里,M 是一个 BigInteger,10^e 用于确定小数点的位置。我想把这些数字除以。当商大于 1 时,我可以进行整数除法以确定小数点应该在哪里。当分子的大小大于分母时,整数除法的结果小于 1。我怎么知道小数应该在哪里?

请注意,为了在不损失精度的情况下执行除法,我在除法之前将分子乘以 10 的大幂,例如 10^24。

我试过对指数进行微分(例如 10^(e1 - e2))。这在大多数情况下会产生正确的答案,但有时指数会偏离 1。当分子大于分母时,也会发生这种情况。

为了说明这个问题,请执行以下操作: 7210^2 / 3510^2 = ~2.06 但是对指数进行微分会得到 ~0.206。

注意:我知道以 2 为基数更适合指数项,我的 BigInteger 类使用以 2 为基数的数字,但我也不知道如何确定小数点应该与以 2 为基数的位置。此外,该类是用 AssemblyScript 编写的,其语法与 TypeScript 相似,后者类似于 JavaScript。我无法使用外部包。

完全安装:https://github.com/Web3-API/as-bigint/blob/main/assembly/BigFloat.ts

除法功能:

  div(other: BigFloat, minPrecision: i32 = this.minPrecision): BigFloat {
    let dividend = this.mantissa;
    let divisor = other.mantissa;
    // divide with padding to maintain precision
    let dividendLength = dividend.toString().length - (dividend.isNegative ? 1 : 0);
    let divisorLength = divisor.toString().length - (divisor.isNegative ? 1 : 0);
    const lengthDiff = dividendLength - divisorLength;
    const padding = minPrecision - (lengthDiff < 0 ? lengthDiff : 0);
    dividend = BigFloat.mulBigIntPowTen(dividend, padding);
    const mantissa: BigInt = dividend.div(divisor);
    // calculate exponent
    let exponent: i32;
    const gteZero: boolean = this.mantissa.magCompareTo(other.mantissa) >= 0;
    if (gteZero) {
      const naiveDiv: BigInt = this.mantissa.div(other.mantissa);
      const naiveDivLen: i32 = naiveDiv.toString().length;
      exponent = naiveDiv.isNegative ? naiveDivLen - 1 : naiveDivLen;
    } else {
      exponent = this.e - other.e;
    }
    return new BigFloat(mantissa, exponent, this.minPrecision);
  }

测试用例(查看“从分数构造”部分): https://github.com/Web3-API/as-bigint/blob/main/assembly/__tests__/BigFloat_read_write.spec.ts

此测试用例由于小数点位置的差一错误而失败:

numerator = BigInt.fromString("23627");
denominator = BigInt.fromString("1093746923469083704986");
bigFloat = BigFloat.fromFraction(numerator, denominator, 30);
expect(bigFloat.toString(30)).toStrictEqual("0.000000000000000021601889333833");
javascript 精度 biginteger bigdecimal 任意精度

评论

0赞 Jonas Wilms 4/24/2021
你能用测试用例分享你的具体实现吗?
0赞 Kris B. 4/25/2021
添加了要发布的链接和示例
0赞 Bergi 4/25/2021
"以 M*10^e 的形式出现,其中 10^0 表示数字介于 [0.1, 1) 之间。- 如果是大整数,那就不太好了。M
0赞 Kris B. 4/25/2021
它确实有效。像 23.45 这样的数字通过存储整数 2345 和指数值 2 表示为 0.2345 * 10^2。隐含了 0.2345 中的小数位,必要时用指数项进行调整。这与标准浮点的存储方式非常相似:rfwireless-world.com/Tutorials/...

答: 暂无答案