You should multiply the numerator to accommodate the number of digits you need, perform the division and then divide with normal floating point division.

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

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

By only converting from BigInt to Number at the "end", you will lose the least precision.

More precision

If you need more than 16 digits precision and need decimals, then you'll need to throw your own implementation of a kind of BigDecimal API, or use an existing one.

Here is a simple one using BigInt as its base type, combined with a configuration that determines how many digits (from the right) of each such BigInt should be interpreted as decimals (digits in the fractional part). That last information will for instance be used to insert a decimal separator when outputting the number as a string.

class BigDecimal {
    // Configuration: private constants
    static #DECIMALS = 18; // Number of decimals on all instances
    static #SHIFT = 10n ** BigInt(BigDecimal.#DECIMALS); // Derived constant
    static #fromBigInt = Symbol();  // Secret to allow construction with given #n value
    #n; // the BigInt that will hold the BigDecimal's value multiplied by #SHIFT
    constructor(value, convert) {
        if (value instanceof BigDecimal) return value;
        if (convert === BigDecimal.#fromBigInt) { // Can only be used within this class
            this.#n = value;
            return;
        }
        const [ints, decis] = String(value).split(".").concat("");
        this.#n = BigInt(ints + decis.padEnd(BigDecimal.#DECIMALS, "0")
                                     .slice(0, BigDecimal.#DECIMALS));
    }
    divide(num) {
        return new BigDecimal(this.#n * BigDecimal.#SHIFT / new BigDecimal(num).#n, BigDecimal.#fromBigInt);
    }
    toString() {
        let s = this.#n.toString().replace("-", "").padStart(BigDecimal.#DECIMALS+1, "0");
        s = (s.slice(0, -BigDecimal.#DECIMALS) + "." + s.slice(-BigDecimal.#DECIMALS))
               .replace(/(\.0*|0+)$/, "");
        return this.#n < 0 ? "-" + s : s;
    }
}

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

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

Addendum: in a later Q&A I enriched this class with add, subtract, multiply and rounding features.

Answer from trincot on Stack Overflow
Top answer
1 of 2
48

You should multiply the numerator to accommodate the number of digits you need, perform the division and then divide with normal floating point division.

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

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

By only converting from BigInt to Number at the "end", you will lose the least precision.

More precision

If you need more than 16 digits precision and need decimals, then you'll need to throw your own implementation of a kind of BigDecimal API, or use an existing one.

Here is a simple one using BigInt as its base type, combined with a configuration that determines how many digits (from the right) of each such BigInt should be interpreted as decimals (digits in the fractional part). That last information will for instance be used to insert a decimal separator when outputting the number as a string.

class BigDecimal {
    // Configuration: private constants
    static #DECIMALS = 18; // Number of decimals on all instances
    static #SHIFT = 10n ** BigInt(BigDecimal.#DECIMALS); // Derived constant
    static #fromBigInt = Symbol();  // Secret to allow construction with given #n value
    #n; // the BigInt that will hold the BigDecimal's value multiplied by #SHIFT
    constructor(value, convert) {
        if (value instanceof BigDecimal) return value;
        if (convert === BigDecimal.#fromBigInt) { // Can only be used within this class
            this.#n = value;
            return;
        }
        const [ints, decis] = String(value).split(".").concat("");
        this.#n = BigInt(ints + decis.padEnd(BigDecimal.#DECIMALS, "0")
                                     .slice(0, BigDecimal.#DECIMALS));
    }
    divide(num) {
        return new BigDecimal(this.#n * BigDecimal.#SHIFT / new BigDecimal(num).#n, BigDecimal.#fromBigInt);
    }
    toString() {
        let s = this.#n.toString().replace("-", "").padStart(BigDecimal.#DECIMALS+1, "0");
        s = (s.slice(0, -BigDecimal.#DECIMALS) + "." + s.slice(-BigDecimal.#DECIMALS))
               .replace(/(\.0*|0+)$/, "");
        return this.#n < 0 ? "-" + s : s;
    }
}

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

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

Addendum: in a later Q&A I enriched this class with add, subtract, multiply and rounding features.

2 of 2
-1

Here's a helper function that cuts down both numbers by the same factor until they can be converted and divided without error.

function bigint_divide(/** @type {bigint} */ num, /** @type {bigint} */ dden) {
    let max_int = BigInt(Number.MAX_SAFE_INTEGER)
    let num_abs = num * (num > 0n ? 1n : -1n)
    let den_abs = den * (den > 0n ? 1n : -1n)
    let bigger_abs = num_abs > den_abs ? num_abs : den_abs
    let factor = 1n
    while(bigger_abs > max_int) {
        factor *= 10n
        bigger_abs /= 10n
    }
    num /= factor
    den /= factor
    return Number(num) / Number(den)
}

There may be precision lost by applying the factor but it's the only way to get to a floating point value somehow. This function mathematically does the same as the multiplication solution from the accepted answer, but finds a fitting factor itself without the caller having to worry about it.

🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Operators › Division
Division (/) - JavaScript | MDN
For BigInt division, the result is the quotient of the two operands truncated towards zero, and the remainder is discarded. A RangeError is thrown if the divisor y is 0n.
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › BigInt
BigInt - JavaScript | MDN
Addition (+) involving a string and a BigInt returns a string. Division (/) truncates fractional components towards zero, since BigInt is unable to represent fractional quantities.
🌐
GitHub
github.com › qntm › big-round
GitHub - qntm/big-round: Custom rounding behaviour for JavaScript BigInt arithmetic
roundingMode must be one of the enumerated values provided by ROUNDING_MODE (q.v.). Returns a new function divide(a, b), where a must be a BigInt, the dividend. b must be a BigInt, the divisor.
Author   qntm
🌐
JavaScript.info
javascript.info › tutorial › the javascript language › miscellaneous
BigInt
BigInt can mostly be used like a regular number, for example: ... Please note: the division 5/2 returns the result rounded towards zero, without the decimal part.
🌐
W3Schools
w3schools.com › js › js_bigint.asp
JavaScript BigInt
Like numbers, bigint literals support several bases: ... let hex = 0x20000000000003n; let oct = 0o400000000000000003n; let bin = 0b100000000000000000000000000000000000000000000000000011n; Try it Yourself » · Maximum safe integer in JavaScript is 9007199254740991.
🌐
LogRocket
blog.logrocket.com › home › how to use javascript’s bigint
How to use JavaScript's BigInt - LogRocket Blog
June 4, 2024 - This fact is extended to the division operation, which can sometimes return a decimal dividend, such as in 7 / 4 = 1.75. Hence, because of this, BigInt values will always be rounded to 0.
🌐
npm
npmjs.com › package › divide-bigint
divide-bigint - npm
import divide from 'divide-bigint' divide(5000000000000000000000000n, 2000000000000000000000000n) divide(5n, 2) divide(5, 2n) divide(5, 2) // -> 2.5
      » npm install divide-bigint
    
Published   May 23, 2019
Version   1.0.4
Find elsewhere
🌐
GitHub
github.com › tc39 › proposal-bigint › issues › 157
Change of the bigint division operator · Issue #157 · tc39/proposal-bigint
April 9, 2018 - Regarding the BigInt division operator, I suggest that it returns a Number (floating point result) instead of a BigInt and to add a BigInt.tdiv(a, b) method which returns the truncated quotient of a and b instead. The rationale is: It reduces the changes with the current Javascript i.e.
Author   bellard
🌐
Stack Overflow
stackoverflow.com › questions › 47381414 › javascript-bigint-division
numbers - Javascript bigint division - Stack Overflow
According to another answer: https://stackoverflow.com/a/2803010/607033 js integers are accurate up to 53 bits. So this division limit might be close to that value, maybe a few bits lower.
🌐
Stack Overflow
stackoverflow.com › questions › 51744959 › how-to-get-the-result-of-a-javascript-bigint-division-in-significants-and-expone
How to get the result of a Javascript BigInt division in significants and exponent - Stack Overflow
It also does not work well with zero and negative numbers. ... You can use Basenumber.js to make a division between two BigIntegers and then represent it with an exponent with n significant digits:
🌐
GeeksforGeeks
geeksforgeeks.org › javascript-rangeerror-bigint-divison-by-zero
JavaScript RangeError: BigInt divison by Zero | GeeksforGeeks
June 5, 2023 - This means that BigInt can represent very large numbers, but it also means that BigInt must follow certain mathematical rules. In particular, division by zero is mathematically undefined and impossible.
🌐
Fabrice Bellard
bellard.org › quickjs › jsbignum.html
Javascript Bignum Extensions
The builtin operators are modified ... integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result....
🌐
DEV Community
dev.to › lavary › integer-division-in-javascript-explained-fai
Integer division in JavaScript explained - DEV Community
March 4, 2023 - The division operator in JavaScript (/) divides two numbers (dividend and divisor) and returns the quotient as a floating point number (rather than the classic quotient and a remainder).
🌐
JavaScript in Plain English
javascript.plainenglish.io › javascript-daily-tips-67-how-to-use-javascripts-bigint-for-arbitrary-precision-arithmetic-080a6204ba09
JavaScript Daily Tips #67: How to Use JavaScript’s BigInt for Arbitrary-Precision Arithmetic | by Mariosdev | JavaScript in Plain English
December 9, 2024 - By the end of this article, you’ll not only understand how BigInt works but also how to use it effectively in your projects. JavaScript’s Number type uses the IEEE 754 double-precision floating-point format, which can safely represent integers in the range of -2<sup>53</sup> + 1 to 2<sup>53</sup> - 1.
Top answer
1 of 2
3

In general...

...mixing number and BigInt is asking for trouble, which is why no math operators will let you do it and explicit conversion is required.

(Note: Decimal is on the horizon, which will apply here when it matures.)

If you want a number result...

...convert the BigInt to a number before doing the calculation; beware that the conversion may be lossy for very large numbers (this is the point of BigInt), specifically numbers above Number.MAX_SAFE_INTEGER or below Number.MIN_SAFE_INTEGER:

let n = 100n;
let x = 0.1;
let result = Number(n) / x;
console.log(result);

If you want a BigInt result...

...it's more complicated, because you have to decide what to do with a fractional result. (Your example won't have a fractional result, but the general case will.) You could go through number, but again that's a potentially lossy operation:

let n = 100n;
let x = 0.1;
let result = BigInt(Number(n) / x); // Throws if the result is fractional
// let result = BigInt(Math.round(Number(n) / x)); // Rounds instead of throwing
console.log(result.toString());

If you can refactor the operation so you can express it in whole numbers, that makes it a lot easier, because then you can make x a BigInt. For instance, in your specific case, / 0.1 is the same as * (1 / 0.1) which is * 10:

let n = 100n;
let x = 10n;
let result = n * x;
console.log(result.toString());

...but that's just that specific case.

You'll probably find you need to handle it on a case-by-case basis, trying to avoid doing the operation. When you can't, and the divisor is fractional, a round-trip through number may be unavoidable.

2 of 2
-2

Just Convert the bigint to number. It will Work.

let n = 100n;
let x = 0.1;
console.log(Number(n)/x); 

It will Return Result 1000