13
13
package java .lang
14
14
15
15
import java .lang .constant .{Constable , ConstantDesc }
16
- import java .math .BigInteger
17
16
18
17
import scala .scalajs .js
19
18
@@ -233,9 +232,11 @@ object Float {
233
232
fractionalPartStr : String , exponentStr : String ,
234
233
zDown : scala.Float , zUp : scala.Float , mid : scala.Double ): scala.Float = {
235
234
235
+ val bigIntImpl = BigIntImpl .getImpl()
236
+
236
237
// 1. Accurately parse the string with the representation f × 10ᵉ
237
238
238
- val f : BigInteger = new BigInteger (integralPartStr + fractionalPartStr)
239
+ val f : bigIntImpl. Repr = bigIntImpl.fromString (integralPartStr + fractionalPartStr)
239
240
val e : Int = Integer .parseInt(exponentStr) - fractionalPartStr.length()
240
241
241
242
/* Note: we know that `e` is "reasonable" (in the range [-324, +308]). If
@@ -268,24 +269,23 @@ object Float {
268
269
269
270
val mExplicitBits = midBits & ((1L << mbits) - 1 )
270
271
val mImplicit1Bit = 1L << mbits // the implicit '1' bit of a normalized floating-point number
271
- val m = BigInteger .valueOf (mExplicitBits | mImplicit1Bit)
272
+ val m = bigIntImpl.fromUnsignedLong53 (mExplicitBits | mImplicit1Bit)
272
273
val k = biasedK - bias - mbits
273
274
274
275
// 3. Accurately compare f × 10ᵉ to m × 2ᵏ
275
276
276
- @ inline def compare (x : BigInteger , y : BigInteger ): Int =
277
- x.compareTo(y)
277
+ import bigIntImpl .{multiplyBy2Pow , multiplyBy10Pow }
278
278
279
279
val cmp = if (e >= 0 ) {
280
280
if (k >= 0 )
281
- compare(multiplyBy10Pow(f, e), multiplyBy2Pow(m, k))
281
+ bigIntImpl. compare(multiplyBy10Pow(f, e), multiplyBy2Pow(m, k))
282
282
else
283
- compare(multiplyBy2Pow(multiplyBy10Pow(f, e), - k), m) // this branch may be dead code in practice
283
+ bigIntImpl. compare(multiplyBy2Pow(multiplyBy10Pow(f, e), - k), m) // this branch may be dead code in practice
284
284
} else {
285
285
if (k >= 0 )
286
- compare(f, multiplyBy2Pow(multiplyBy10Pow(m, - e), k))
286
+ bigIntImpl. compare(f, multiplyBy2Pow(multiplyBy10Pow(m, - e), k))
287
287
else
288
- compare(multiplyBy2Pow(f, - k), multiplyBy10Pow(m, - e))
288
+ bigIntImpl. compare(multiplyBy2Pow(f, - k), multiplyBy10Pow(m, - e))
289
289
}
290
290
291
291
// 4. Choose zDown or zUp depending on the result of the comparison
@@ -300,11 +300,75 @@ object Float {
300
300
zUp
301
301
}
302
302
303
- @ inline private def multiplyBy10Pow (v : BigInteger , e : Int ): BigInteger =
304
- v.multiply(BigInteger .TEN .pow(e))
303
+ /** An implementation of big integer arithmetics that we need in the above method. */
304
+ private sealed abstract class BigIntImpl {
305
+ type Repr
306
+
307
+ def fromString (str : String ): Repr
308
+
309
+ /** Creates a big integer from a `Long` that needs at most 53 bits (unsigned). */
310
+ def fromUnsignedLong53 (x : scala.Long ): Repr
311
+
312
+ def multiplyBy2Pow (v : Repr , e : Int ): Repr
313
+ def multiplyBy10Pow (v : Repr , e : Int ): Repr
314
+
315
+ def compare (x : Repr , y : Repr ): Int
316
+ }
317
+
318
+ private object BigIntImpl {
319
+ /** Get the best available implementation of big integers for the given platform.
320
+ *
321
+ * If JS bigint's are supported, use them. Otherwise fall back on
322
+ * `java.math.BigInteger`.
323
+ *
324
+ * We need a `linkTimeIf` here because the JS bigint implementation uses
325
+ * the `**` operator, which does not link when `esVersion < ESVersion.ES2016`.
326
+ */
327
+ @ inline def getImpl (): BigIntImpl = {
328
+ import scala .scalajs .LinkingInfo ._
329
+ linkTimeIf[BigIntImpl ](esVersion >= ESVersion .ES2020 ) {
330
+ JSBigInt
331
+ } {
332
+ JBigInteger
333
+ }
334
+ }
335
+
336
+ private object JSBigInt extends BigIntImpl {
337
+ type Repr = js.BigInt
305
338
306
- @ inline private def multiplyBy2Pow (v : BigInteger , e : Int ): BigInteger =
307
- v.shiftLeft(e)
339
+ @ inline def fromString (str : String ): Repr = js.BigInt (str)
340
+
341
+ /* The 53-bit restriction allows us to take twice 31 bits, which avoids
342
+ * the issue of considering the bit 31 as a sign bit in the rhs of the |.
343
+ * It also guarantees we can safely build a `Double` out of it.
344
+ */
345
+ @ inline def fromUnsignedLong53 (x : scala.Long ): Repr =
346
+ js.BigInt ((x >>> 31 ).toInt.toDouble * 2147483648.0 + (x.toInt & 0x7fffffff ).toDouble)
347
+
348
+ @ inline def multiplyBy2Pow (v : Repr , e : Int ): Repr = v << js.BigInt (e)
349
+ @ inline def multiplyBy10Pow (v : Repr , e : Int ): Repr = v * (js.BigInt (10 ) ** js.BigInt (e))
350
+
351
+ @ inline def compare (x : Repr , y : Repr ): Int = {
352
+ if (x < y) - 1
353
+ else if (x > y) 1
354
+ else 0
355
+ }
356
+ }
357
+
358
+ private object JBigInteger extends BigIntImpl {
359
+ import java .math .BigInteger
360
+
361
+ type Repr = BigInteger
362
+
363
+ @ inline def fromString (str : String ): Repr = new BigInteger (str)
364
+ @ inline def fromUnsignedLong53 (x : scala.Long ): Repr = BigInteger .valueOf(x)
365
+
366
+ @ inline def multiplyBy2Pow (v : Repr , e : Int ): Repr = v.shiftLeft(e)
367
+ @ inline def multiplyBy10Pow (v : Repr , e : Int ): Repr = v.multiply(BigInteger .TEN .pow(e))
368
+
369
+ @ inline def compare (x : Repr , y : Repr ): Int = x.compareTo(y)
370
+ }
371
+ }
308
372
309
373
private def parseFloatHexadecimal (integralPartStr : String ,
310
374
fractionalPartStr : String , binaryExpStr : String ): scala.Float = {
0 commit comments