Patashu / break_eternity.js

A Javascript numerical library to represent numbers as large as 10^^1e308 and as small as 10^-10^^1e308. Sequel to break_infinity.js, designed for incremental games.
MIT License
120 stars 43 forks source link

Can't convert BigInt to Decimal without setting its value to 0 #142

Open James103 opened 1 year ago

James103 commented 1 year ago

Currently (latest break_eternity.js version as of 2023-01-07), attempting to convert a BigInt value to Decimal will return 0. Furthermore, a string that represents a number (generated by BigInt.toString()) will also return 0 if the number the string represents is at least 21024.

Console output with test cases:

new Decimal(String(2n**1022n)).toString() // 1
'4.494232837155819e307'

new Decimal(String(2n**1032n)).toString() // 2
'0'

new Decimal(1234n).toString() // 3
'0'

new Decimal(2n**1234n).toString() // 4
'0'
  1. Correct
  2. Incorrect; should be 21032 or about 4.602094e310
  3. Incorrect; should be 1234
  4. Incorrect; should be 21234 or about 2.958112e371

Discovered whilst writing migration code for an incremental game to convert various save data from BigInt values to their proper Decimals.

Patashu commented 1 year ago

Woah, I haven't seen this '2n' thing before. Is it a new Javascript feature?

James103 commented 1 year ago

Woah, I haven't seen this '2n' thing before. Is it a new Javascript feature?

The syntax used describes something called BigInts, which are supported on the most recent version of all major browsers. BigInts effectively allow storing numbers much larger than 21024 with full precision (down to the nearest whole number), with their size effectively only being limited only by available memory.

For more information on BigInts, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt

Patashu commented 1 year ago

Cutting edge! I'll take a look at supporting BigInts if I find the time and mood.

James103 commented 1 year ago

You can convert a BigInt to a String with String(bigint) or bigint.toString() and you can construct a Decimal from a string of digits with new Decimal(string). However, Decimal.fromString fails to properly parse strings of digits that are more than 309 digits long, as such strings become Infinity when coerced to Number.

Number("1".repeat(309))
1.1111111111111112e+308

Number("1".repeat(310))
Infinity
Patashu commented 1 year ago

I guess it'd be sufficient to detect the string is longer than 300 digits, grab the first 18 of them, and turn it into mantissa and exponent.

1231234md5 commented 1 year ago

145 will fix it

jakub791 commented 1 year ago

I guess it'd be sufficient to detect the string is longer than 300 digits, grab the first 18 of them, and turn it into mantissa and exponent.

Couldn't you toString() the bigint, remove the n from the string then let toString() method do it's job as usual?

1231234md5 commented 1 year ago

I guess it'd be sufficient to detect the string is longer than 300 digits, grab the first 18 of them, and turn it into mantissa and exponent.

Couldn't you toString() the bigint, remove the n from the string then let toString() method do it's job as usual?

but that's what #145 does.