GitHub - js-choi/proposal-bigint-math: Draft specification for supporting...

There is a proposal to make Math functions working with BigInts - GitHub - js-choi/proposal-bigint-math: Draft specification for supporting BigInts in JavaScript’s Ma . I am not the auther and cannot find any discussion, so I am creating this post.

Do you have use cases for one of the below functions?

  • abs
  • max
  • min
  • sign
  • sqrt
  • cbrt
  • hypot
  • log10
  • log2
  • one of other functions

0 voters

Would you like to have one of the below functions:

  • bitLength
  • nthRoot
  • gcd
  • modPow
  • modInverse
  • isPrime
  • factorization
  • random

0 voters

Note: bit length and log base 2 are essentially the same thing.

I do have use cases for a clz64, though.

2 Likes

@claudiameadows , hello, thanks for you reply!

log2(x) can be different from bitLength(x) if to allow it to return floating point value... which can be useful sometimes (the current proposal, seems, wants to return bigint values, so you are right)

I think, clz can be computed from bitLength:
clz64(x) = 64 - bitLength(x), where x is a 64 bit bigint
clz128(x) = 128 - bitLength(x), where x is a 128 bit bigint

1 Like

Technically yes, but how often are you to be computing non-floored log2s of large integers? Also, floats can't cover the entirety of the result space, so that limits its applicability, and non-integer results for integer input I believe are all transcendental anyways, so you're stuck with infinite decimals regardless.

I wouldn't be against using GitHub - tc39/proposal-decimal: Built-in decimal datatype in JavaScript to represent its return value, though. But using standard floats is a bad idea.

1 Like

A little excercise. Given

  • X: BigInt
  • such that log2(X) > Number.MAX_VALUE

What is the lower bound of:

  • bitLength(X) >= ?

(and where do you store those bits)?

4 Likes

It would itself return a bigint, so that's not really a question. And bit length would just return the least amount of bits that could represent the bigint in question as a two's complement integer (i.e. one greater than the floored binary logarithm of that value).

Your argument was that floats can't cover the entirety of log2's result space. I claim the practical (as in physically possible) result space is smaller than the range of double-precision float.

1 Like

I'd recommend stating that (with explanations of result ranges, etc.) as a bug against that repo, then. :wink:

I’m taking a look at Yaffle’s poll, and it looks like several people have answered that they would find BigInt sqrt, cbrt, and log10 useful. I have been long wondering whether anyone would actually find these useful (they have been removed from the spec due to lack of use cases; the engines don’t want to implement anything without use cases), so it would be great if anyone could share their specific use cases for BigInt sqrt, cbrt, or log10.

(My current vision is that this initial proposal would overload only a few first Math methods, and that the initial proposal would open up the way to new proposals that would further extend Math with type-overloaded methods, like popcnt or modPow or bitLength (a truncating log2).)

2 Likes

log10 is useful for plotting on logarithmic scale, and string formatting. You may want to calculate something with BigInts and then show the result truncated to a number of significant digits.
edit: Well you could convert to string first and then truncate the string. But then you won't have proper rounding, unless you tinker with the string some more.

That being said, I would find it really weird if logN truncated the result to BigInt, instead of returning a Number. It would complicate the plotting on logarithmic scale use case. You'd basically need to first multiply by 1000 and then do the log10 to get a usable result.

edit 2: damn I'm dumb today. Multiplying of course wouldn't help at all, it would only add a constant to all results, but not make them "smoother". You'd need to pow like log10(x ** 20) to get a smoother plot.

1 Like

I thought for string display you divide by a power of 10, not take a decimal logarithm.

Yea but what power of 10? If you want 50 significant digits, you divide by 10 ** (log10(x) - 50).

It's num / (10 ** precision) mod a few edge cases. Logarithms simply count digits and aside from very large bignum arithmetic you can get away by just repeated division because the time it takes to do that is negligible compared to the cost of everything else and all you really need is a floored base 10 logarithm.

For bigints, as long as you have a "find first set" or related algorithm (like "count leading zeroes"), you can still do that part extremely efficiently.

This statement is wrong. The link is not even related; I assume you meant to instead link to this function in that code — notice how what it does is approximating log10(x).

When you have x = 10 ** 500, and want to print it in a readable form, you don't cut precision digits; you cut d = (log10(x) - precision) digits and append "E"+d. For example with precision = 5 the output would be "100000E495" (or some other form of the same, like "100000 * 10**495"). You may also cut trailing zeros, but you can only do that after cutting d excess digits, for which you need to know log10(x).

Repeated division is just a silly way of reimplementing logarithm. You could get fancy a use binary search to find the d, which is slightly more efficient and complicated way of reimplementing logarithm.

Yes, "find first set" would help reimplementing floored log10 more efficiently. "count leading zeros" only makes sense for fixed-width integers, not for BigInt.
Question is: why should everyone who wants to stringify large BigInts need to reimplement log10?

I'll stand corrected. I misread the code.

I'm aware, and was trying to implicitly acknowledge this in the comment you quoted. :wink:

Why I said "or related" - there's several ways of doing "find first set". Even something as simple as bit length would also be sufficient (and honestly, that's probably what I should've suggested in the first place).

I do get that concern, but I'm not convinced adding a decimal logarithm is worth it when that could just be addressed by adding .toPrecision to bigints to align with floating point numbers and suddenly nobody's having to roll their own stringifier.

There's of course other use cases, but I wouldn't consider them common by any stretch.

In practice, that's always true. But in theory, a BigInt could be bigger than G(64), as the spec places no hard-coded limits on their size.

It's unfortunate that Map and Set came before BigInts, because (unlike String and Array, whose lengths fit in a 64bit register) their internal size is unbounded, but gets converted to a Float64 by their getter

And floats lose fractional precision as the order-of-magnitude increases