如何将两个原生 JavaScript BigInt 相除并得到一个十进制结果。

27

以下是目前我尝试的方法。我的目标是得到一个12.34

BigInt('12340000000000000000') / BigInt('1000000000000000000')

12n

Number(BigInt('12340000000000000000') / BigInt('1000000000000000000'))

12

顺便提一下,当我使用JSBI库时,它可以按照我期望的方式工作:

JSBI.BigInt('12340000000000000000') / JSBI.BigInt('1000000000000000000');

12.34

这不可能本地实现吗?


2
Number(BigInt('x')) / Number(BigInt('y'))怎么样?也就是说,两个本地数字的普通本地除法? - Pointy
1
否则,据我所知,您无法这样做,因为在Java中与BigInteger相关的内容与BigDecimal相关的内容不同。 - Pointy
5
Number(BigInt('12340000000000000001')) 无法正常工作,因为使用 BigInt 的目的是保持完整的精度,如果只是将它转换成一个数字,就会丢失精度。结果将是 12340000000000000000 - robmisio
1
@Pointy 对于你的第二条评论...是的,我想这可能是做不到的,但很奇怪,官方推荐的回退库可以做到。</shrug> - robmisio
but weird that the lib that is officially recommended as the fallback could do it That's because your then just doing Number / Number,.. eg. You can do that calc without using JSBI.. In pure JS -> 12340000000000000000 / 1000000000000000000 = 12.34 - Keith
2
在JSBI中的等效操作是 JSBI.divide('12340000000000000000', '1000000000000000000') - Keith
1个回答

37

您应该将分子乘以适合所需位数的数字,执行除法,然后使用普通浮点除法进行除法运算。

(在支持 BigInt 的浏览器中运行,例如 Chrome)

您应该将分子乘以适合所需位数的数字,执行除法,然后使用普通浮点除法进行除法运算。

(在支持 BigInt 的浏览器中运行,例如 Chrome)

var a = 12340000000000000000n;
var b =  1000000000000000000n;

console.log(Number(a * 100n / b) / 100);

只在“最后”转换成数字,您将损失最少的精度。

更高的精度

如果您需要超过16位数字的精度并且需要小数,则需要自己实现一种BigDecimal API或使用现有API。

这里有一个简单的实现,它以BigInt作为其基础类型,并结合配置来确定应将每个这样的BigInt的多少位数字(从右侧)解释为小数(分数中的数字)。例如,最后一个信息将用于在将数字输出为字符串时插入小数分隔符。

class BigDecimal {
    constructor(value) {
        let [ints, decis] = String(value).split(".").concat("");
        decis = decis.padEnd(BigDecimal.decimals, "0");
        this.bigint = BigInt(ints + decis);
    }
    static fromBigInt(bigint) {
        return Object.assign(Object.create(BigDecimal.prototype), { bigint });
    }
    divide(divisor) { // You would need to provide methods for other operations
        return BigDecimal.fromBigInt(this.bigint * BigInt("1" + "0".repeat(BigDecimal.decimals)) / divisor.bigint);
    }
    toString() {
        const s = this.bigint.toString().padStart(BigDecimal.decimals+1, "0");
        return s.slice(0, -BigDecimal.decimals) + "." + s.slice(-BigDecimal.decimals)
                .replace(/\.?0+$/, "");
    }
}
BigDecimal.decimals = 18; // Configuration of the number of decimals you want to have.

// Demo
var a = new BigDecimal("123456789123456789876");
var b = new BigDecimal( "10000000000000000000");

console.log(a.divide(b).toString());

需要注意的是,这需要支持 BigInt 的浏览器(在撰写本文时为 Chrome)。


1
请看我的补充答案。 - trincot
1
@noririco,它在typescript中输出相同的结果:“12.345678912345678987” - trincot
1
@trincot 谢谢!我的错误是 static decimals = 18; 不是 static - noririco
1
原因是toString中的字符串s没有足够的数字来在正确的位置插入小数点。现在已经修复了。感谢您发现这个问题。 - trincot
2
顺便提一下,我有一个版本,其中包括加法、减法、乘法和四舍五入作为对JavaScript中的BigDecimal的答案。链接 - trincot
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接