Как разделить два нативных JavaScript BigInt и получить десятичный результат

Вот что я пробовал до сих пор. Я хочу получить 12.34:

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

12n

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

12

FWIW, когда я использую библиотеку JSBI, она работает так, как мне хотелось бы:

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

12.34

Разве это не возможно изначально?


person robmisio    schedule 28.01.2019    source источник
comment
А как насчет Number(BigInt('x')) / Number(BigInt('y')), то есть простого нативного деления двух нативных чисел?   -  person Pointy    schedule 28.01.2019
comment
В противном случае, насколько я могу судить, вы не можете этого сделать, так как нет ничего, связанного с BigInt, поскольку BigDecimal связано с BigInteger в Java.   -  person Pointy    schedule 28.01.2019
comment
@Pointy Number(BigInt('12340000000000000001')) не будет работать, потому что весь смысл использования BigInt заключается в сохранении полной точности, которую вы потеряете, если просто преобразуете ее в число. Результатом этого будет 12340000000000000000.   -  person robmisio    schedule 28.01.2019
comment
@Pointy К вашему второму комментарию ... да, я полагаю, что это может быть невыполнимо, но странно, что библиотека, официально рекомендованная в качестве запасного варианта, может это сделать ‹ / пожимает плечами ›   -  person robmisio    schedule 28.01.2019
comment
but weird that the lib that is officially recommended as the fallback could do it Это потому, что вы тогда просто делаете Number / Number,.. например. Вы можете сделать этот расчет без использования JSBI. В чистом JS -> 12340000000000000000 / 1000000000000000000 = 12.34   -  person Keith    schedule 28.01.2019
comment
Эквивалент в JSBI будет JSBI.divide('12340000000000000000', '1000000000000000000')   -  person Keith    schedule 28.01.2019


Ответы (1)


Вы должны умножить числитель, чтобы разместить необходимое количество цифр, выполнить деление, а затем разделить с обычным делением с плавающей запятой.

(Запускать в браузере, который поддерживает BigInt, например Chrome)

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

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

Преобразуя в число только в конце, вы потеряете наименьшую точность.

Больше точности

Если вам нужна точность более 16 цифр, и нужны десятичные дроби, вам нужно создать собственную реализацию типа BigDecimal 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 на момент написания статьи).

person trincot    schedule 28.01.2019
comment
Теперь, как я могу сделать то же самое, если мне нужна 18-значная точность (например, до .0000000000000000001), если это сделает этот множитель/делитель сам по себе BigInt? - person robmisio; 29.01.2019
comment
Смотрите дополнение к моему ответу. - person trincot; 29.01.2019
comment
В машинописи это вернет .12345678912345678987 - person noririco; 04.04.2021
comment
@noririco, он дает тот же результат в typescript: 12.345678912345678987 - person trincot; 04.04.2021
comment
@trincot СПАСИБО! моя ошибка была static decimals = 18; не была static - person noririco; 04.04.2021
comment
@trincot еще один вопрос: если я вычислю 10000000 / 4294967296, я получу .2328306436538696 вместо 0.002328306436538696, что может быть причиной этого? - person noririco; 05.04.2021
comment
Причина заключалась в том, что в строке s в toString не хватало цифр для вставки десятичной точки в правильном месте. Исправлено сейчас. Спасибо, что заметили это. - person trincot; 05.04.2021
comment
К вашему сведению, у меня есть версия с добавлением, вычитанием, умножением и округлением в качестве ответа на BigDecimal в JavaScript. - person trincot; 05.04.2021
comment
@trincot Да благословит тебя БОГ и да благословит БОГ Соединенные Штаты из stackoverflow - person noririco; 05.04.2021