tc39 / proposal-bigint-math

Draft specification for supporting BigInts in JavaScript’s Math methods.

Home Page:https://tc39.es/proposal-bigint-math/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BigInt log10 or log2?

js-choi opened this issue · comments

The current plan is to remove BigInt support from all transcendental functions. However, there are exact cases for log10 and log2.

Should we support Math.log10(100n) or Math.log2(16n)? My gut says yes, and we can truncate non-integer results, as with BigInt division.

Changes to explainer and spec have been pushed. log2 and log10 now truncate towards zero.

#4 states that a reason against transcendental functions is that "processing time would need to be huge". I agree, and would like to point out that this will apply to log10 as well. Computing log10 will be algorithmically equivalent to doing my_bigint.toString().length. (log2 will be very fast. For the record, this statement does depend on implementation choices and is currently true for the major browsers; there are also BigInt libraries in existence for which log10 would be fast and log2 would be slow.)

log2 needs a specification for what log2(0n) should do. Throw an exception?

Also, note that the values returned by log2 will never be outside a range that Number could handle with ease (current browser implementations allow a million or a billion bits, so that'd even be int32 range; allowing for the (unlikely?) possibility of future growth there still means that MAX_SAFE_INTEGER range would be plenty). So you could consider having log2 return a Number, which would have the benefit that it wouldn't need to be rounded to integers (though of course there would be a loss of precision once the input exceeds a certain range). I don't feel strongly about this, it's just an idea.

If log2 always truncates, maybe it would make sense to call it bitLength instead? That would also address the 0n question. (Of course, the exact relation between these functions is bitLength(x) == log2(x) + 1.)

Speaking of truncation, the explainer currently says "log2(2n ** 49n - 1n) would return 49n", whereas truncating behavior means returning 48n for that input.

#4 states that a reason against transcendental functions is that "processing time would need to be huge". I agree, and would like to point out that this will apply to log10 as well. Computing log10 will be algorithmically equivalent to doing my_bigint.toString().length. (log2 will be very fast. For the record, this statement does depend on implementation choices and is currently true for the major browsers; there are also BigInt libraries in existence for which log10 would be fast and log2 would be slow.)

This is essential implementer feedback, thank you. I would be happy to drop log10 if implementation complexity would be large. However, would complexity really be that large? This might be naïve, but it’s not like the natural logarithm: we should at least be able to perform a simple search over powers of 10, right? Or is it that calculating large powers of 10 would itself have much complexity? (CC: @syg, @codehag)

log2 needs a specification for what log2(0n) should do. Throw an exception?

The specification currently throws a RangeError. I can note this in the spec, too.

Also, note that the values returned by log2 will never be outside a range that Number could handle with ease (current browser implementations allow a million or a billion bits, so that'd even be int32 range; allowing for the (unlikely?) possibility of future growth there still means that MAX_SAFE_INTEGER range would be plenty). So you could consider having log2 return a Number, which would have the benefit that it wouldn't need to be rounded to integers (though of course there would be a loss of precision once the input exceeds a certain range). I don't feel strongly about this, it's just an idea.

Currently, whenever an arithmetic operation or Math function takes a BigInt argument (and doesn’t throw), it returns a BigInt. I think we should continue to match this and return BigInts from log2 when given BigInts.

If log2 always truncates, maybe it would make sense to call it bitLength instead? That would also address the 0n question. (Of course, the exact relation between these functions is bitLength(x) == log2(x) + 1.)

I would rather keep it the same name (the point of this spec is to patch up holes in Math and make BigInts and Numbers more interchangeable as much as practical), but I do not feel strongly about this.

Speaking of truncation, the explainer currently says "log2(2n ** 49n - 1n) would return 49n", whereas truncating behavior means returning 48n for that input.

Good catch. This is a mistake that I actually already fixed right before this comment was posted, in b09db3e.

Closing. log2 and log10 truncation may be developer surprising. Truncating log2 could be codified as a future type-overloaded Math.bitLength method. And there are no other known use cases for truncating log2 or log10.

See also #13 (comment), #14, and #14 (comment).