Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to divide two native JavaScript BigInt's and get a decimal result

Here's what I've tried so far. I'm looking to get a 12.34:

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

12n

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

12

FWIW, when I use the JSBI lib, it's working how I'd like:

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

12.34

Is that not possible natively?

like image 884
robmisio Avatar asked Jan 28 '19 20:01

robmisio


People also ask

Is there BigDecimal in JavaScript?

BigDecimal for Javascript is a pure-Javascript implementation of immutable, arbitrary-precision, signed decimal numbers. BigDecimal supports decimal math with arbitrary precision. For a limited time, we will throw in BigInteger support at no extra charge!

How do you divide numbers in JavaScript?

Division The division operator (/) divides two or more numbers. Example: var a = 50; var b = 20; var c = a / b; Approach: Create the html form to take input from user to perform division operation.

How do you handle large numbers in JavaScript?

To represent integers larger than 2 to the 53rd power minus 1 in JavaScript, we can use the BigInt object to represent the values. It can be manipulated via normal operations like arithmetic operators — addition, subtraction, multiplication, division, remainder, and exponentiation.

Can BigInt store decimal values?

BIGINT is to store large integers from negative 263 through positive 263 – 1. The storage size is eight bytes. BIGINT is intended for special cases where INTEGER range is"not sufficient. DECIMAL Valid values are in the range from negative 1038 +1 through positive 1038 – 1.


1 Answers

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

(Run in browser that supports BigInt, like Chrome)

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

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

By only converting 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 {
    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());

Again, this needs a browser that supports BigInt (Chrome at the time of writing).

like image 196
trincot Avatar answered Sep 21 '22 16:09

trincot