Closed Yaffle closed 3 years ago
Thank you for taking a look at the proposal! As an implementor of a BigInt library, you bring much-needed real-world insight.
I don’t think safe Number integers should be a problem, because in this proposal, sqrt
, cbrt
, log2
, and log10
would all return BigInts when they are given BigInts. And those returned BigInts would be truncated towards 0
, just like BigInt division /
. So:
(3000000000n - 1n) / 1000000000n
already returns 2n
.cbrt(131329n ** 3n - 1n)
would return 131328n
.sqrt(67108865n ** 2n - 1n)
would return 67108864n
.log2(2n ** 49n - 1n)
would return 48n
.log10(10n ** 15n - 1n)
would return 14n
.Does that make sense?
If so, I can edit the explainer to make this clearer.
@js-choi ,
It makes sense, I am just pointing to the fact, that Math.cbrt(131329**3-1) !== Number(Math.cbrt(131329n**3n-1n))
and so you cannot switch between safe integers and bigints. May be this is OK.
while Math.trunc(a / b) === Number(BigInt(a) / BigInt(b))
is always true for safe integers
This is true. This difference is a result of how Ecma 262 defines Number::divide(x, y) to return precisely 𝔽(ℝ(x) / ℝ(y)), while Math.sqrt and so on are currently defined to return implementation-approximated values.
I think this behavior should be okay, but I would also love to hear opinions from anyone else.
so for current plan and for number x
:
Math.floor(Math.sqrt(x))
matches Number(Math.floor(Math.sqrt(BigInt(x))))
,
Math.floor(Math.cbrt(x))
matches Number(Math.floor(Math.cbrt(BigInt(x))))
,
Math.floor(Math.log2(x))
matches Number(Math.floor(Math.log2(BigInt(x))))
,
Math.floor(Math.log10(x))
matches Number(Math.floor(Math.log10(BigInt(x))))
,
when x
is a positive integer and x
is less than 2**49 - 1
and only if special values (a**2
- for sqrt, a**3
- for cbrt, 2**n
- for log2
and 10**n
- for log10
) are speced to produce the exact result or a little greater then result. In most of the web browsers this is true.
@Yaffle: Thank you for the investigation! How did you test these—did you loop through all safe-integer Numbers, and which non-safe-integer Numbers did you also check? And which browsers did you test on?
@js-choi , I have updated my first comment to this issue with the javascript test
@js-choi I have tested on latest Safari, Firefox, Chrome, IE 11 on different operations systems (by using browsers of the visitors of my tool :-) )
Closing. sqrt
, cbrt
, 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 sqrt
, cbrt
, log2
, or log10
.
See also https://github.com/tc39/proposal-bigint-math/issues/13#issuecomment-919472001, https://github.com/tc39/proposal-bigint-math/issues/14, and https://github.com/tc39/proposal-bigint-math/issues/14#issuecomment-918663577.
@js-choi floor(sqrt(s)) is used in Continued Fraction Factorization method - https://github.com/Yaffle/continuedFractionFactorization/blob/main/continuedFractionFactorization.js#L36
Thank you for making me aware of this! I will have to investigate this myself to see how this works. Do you know of any other use cases for truncated BigInt roots?
This would have ramifications for the rest of the proposal, so I might punt BigInt sqrt
to a future proposal while we gather more data. Hopefully the Committee will have more stomach for BigInt sqrt
if it accepts this initial minimal proposal.
@js-choi , I cannot single out other examples for sqrt, but I think, sqrt is definitly useful, although, it could be that more general floor(nthRoot(a, n)) is needed.
Btw, this library needs gcd, bitLength, sqrt, modPow(this one for smal integers), and modInverse
Truncation is the only option with reasonable mathematical properties for BigInt sqrt, and it matches how BigInt division works. It always gives an exact integral answer that's mathematically the most useful and all implementations can agree on. I'm not sure what the controversy here is. Other alternatives such as trying to match the IEEE double rounding errors in Math.cbrt(131329**3-1)
don't make sense — the whole point of using BigInts is avoiding such unpredictable or implementation-defined behavior.
Yeah, gcd and such would be useful.
@waldemarhorwat: As of right now, BigInt sqrt
etc. have been removed due to lack of definite use cases, but some developers seem to think they might be useful, so I’m trying to figure out how with the TC39 Research Incubator Group.
The proposal’s current vision is to punt wholly new methods like Math.gcd
or modPow
to future proposals. This proposal is currently focusing on creating a precedent for such future proposals, with a minimal set of definitely useful type overloads of certain existing Math
methods. So the vision is: We start with overloading Math.min
, max
, sign
, and abs
, and once that advances we make a Math.gcd
/modPow
/etc. proposals, each of which would handle both Numbers and BigInts.
Feedback on this vision would be welcome in #13 and #14!
in my Chrome:
Math.cbrt(131329**3-1)
gives131329
ifMath.cbrt(131329n**3n-1n)
gives131328
then you cannot expect the equal result for all safe integers.the same is for
Math.sqrt(67108865**2 - 1) === 67108865
andMath.log2(2**49 - 1) === 49
,Math.log10(10**15 - 2) === 15
The range for which this holds depends on the accuracy (precision?) of the Math.sqrt and Math.cbrt, for Math.sqrt, I think, it is 0.5ulps, while for Math.cbrt it is implementation defined and limited to some small amount of ulps (4) .
131329**3 - 1 ~= 2**51.00847800299688
67108865**2 - 1 ~= 2**52.00000004299566
2**49 - 1
10**15 - 2 ~= 2**49.82892142331043
Test: