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
@@ -226,9 +225,11 @@ object Float {
226
225
fractionalPartStr : String , exponentStr : String ,
227
226
zDown : scala.Float , zUp : scala.Float , mid : scala.Double ): scala.Float = {
228
227
228
+ val bigIntImpl = BigIntImpl .getImpl()
229
+
229
230
// 1. Accurately parse the string with the representation f × 10ᵉ
230
231
231
- val f : BigInteger = new BigInteger (integralPartStr + fractionalPartStr)
232
+ val f : bigIntImpl. Repr = bigIntImpl.fromString (integralPartStr + fractionalPartStr)
232
233
val e : Int = Integer .parseInt(exponentStr) - fractionalPartStr.length()
233
234
234
235
/* Note: we know that `e` is "reasonable" (in the range [-324, +308]). If
@@ -261,24 +262,23 @@ object Float {
261
262
262
263
val mExplicitBits = midBits & ((1L << mbits) - 1 )
263
264
val mImplicit1Bit = 1L << mbits // the implicit '1' bit of a normalized floating-point number
264
- val m = BigInteger .valueOf (mExplicitBits | mImplicit1Bit)
265
+ val m = bigIntImpl.fromUnsignedLong53 (mExplicitBits | mImplicit1Bit)
265
266
val k = biasedK - bias - mbits
266
267
267
268
// 3. Accurately compare f × 10ᵉ to m × 2ᵏ
268
269
269
- @ inline def compare (x : BigInteger , y : BigInteger ): Int =
270
- x.compareTo(y)
270
+ import bigIntImpl .{multiplyBy2Pow , multiplyBy10Pow }
271
271
272
272
val cmp = if (e >= 0 ) {
273
273
if (k >= 0 )
274
- compare(multiplyBy10Pow(f, e), multiplyBy2Pow(m, k))
274
+ bigIntImpl. compare(multiplyBy10Pow(f, e), multiplyBy2Pow(m, k))
275
275
else
276
- compare(multiplyBy2Pow(multiplyBy10Pow(f, e), - k), m) // this branch may be dead code in practice
276
+ bigIntImpl. compare(multiplyBy2Pow(multiplyBy10Pow(f, e), - k), m) // this branch may be dead code in practice
277
277
} else {
278
278
if (k >= 0 )
279
- compare(f, multiplyBy2Pow(multiplyBy10Pow(m, - e), k))
279
+ bigIntImpl. compare(f, multiplyBy2Pow(multiplyBy10Pow(m, - e), k))
280
280
else
281
- compare(multiplyBy2Pow(f, - k), multiplyBy10Pow(m, - e))
281
+ bigIntImpl. compare(multiplyBy2Pow(f, - k), multiplyBy10Pow(m, - e))
282
282
}
283
283
284
284
// 4. Choose zDown or zUp depending on the result of the comparison
@@ -293,11 +293,71 @@ object Float {
293
293
zUp
294
294
}
295
295
296
- @ inline private def multiplyBy10Pow (v : BigInteger , e : Int ): BigInteger =
297
- v.multiply(BigInteger .TEN .pow(e))
296
+ /** An implementation of big integer arithmetics that we need in the above method. */
297
+ private sealed abstract class BigIntImpl {
298
+ type Repr
299
+
300
+ def fromString (str : String ): Repr
301
+
302
+ /** Creates a big integer from a `Long` that needs at most 53 bits (unsigned). */
303
+ def fromUnsignedLong53 (x : scala.Long ): Repr
304
+
305
+ def multiplyBy2Pow (v : Repr , e : Int ): Repr
306
+ def multiplyBy10Pow (v : Repr , e : Int ): Repr
307
+
308
+ def compare (x : Repr , y : Repr ): Int
309
+ }
310
+
311
+ private object BigIntImpl {
312
+ /** Get the best available implementation of big integers for the given platform.
313
+ *
314
+ * If JS bigint's are supported, use them. Otherwise fall back on
315
+ * `java.math.BigInteger`.
316
+ *
317
+ * We need a `linkTimeIf` here because the JS bigint implementation uses
318
+ * the `**` operator, which does not link when `esVersion < ESVersion.ES2016`.
319
+ */
320
+ @ inline def getImpl (): BigIntImpl = {
321
+ import scala .scalajs .LinkingInfo ._
322
+ linkTimeIf[BigIntImpl ](esVersion >= ESVersion .ES2020 ) {
323
+ JSBigInt
324
+ } {
325
+ JBigInteger
326
+ }
327
+ }
328
+
329
+ private object JSBigInt extends BigIntImpl {
330
+ type Repr = js.BigInt
298
331
299
- @ inline private def multiplyBy2Pow (v : BigInteger , e : Int ): BigInteger =
300
- v.shiftLeft(e)
332
+ @ inline def fromString (str : String ): Repr = js.BigInt (str)
333
+
334
+ // The 53-bit restriction guarantees that the conversion to `Double` is lossless.
335
+ @ inline def fromUnsignedLong53 (x : scala.Long ): Repr = js.BigInt (x.toDouble)
336
+
337
+ @ inline def multiplyBy2Pow (v : Repr , e : Int ): Repr = v << js.BigInt (e)
338
+ @ inline def multiplyBy10Pow (v : Repr , e : Int ): Repr = v * (js.BigInt (10 ) ** js.BigInt (e))
339
+
340
+ @ inline def compare (x : Repr , y : Repr ): Int = {
341
+ if (x < y) - 1
342
+ else if (x > y) 1
343
+ else 0
344
+ }
345
+ }
346
+
347
+ private object JBigInteger extends BigIntImpl {
348
+ import java .math .BigInteger
349
+
350
+ type Repr = BigInteger
351
+
352
+ @ inline def fromString (str : String ): Repr = new BigInteger (str)
353
+ @ inline def fromUnsignedLong53 (x : scala.Long ): Repr = BigInteger .valueOf(x)
354
+
355
+ @ inline def multiplyBy2Pow (v : Repr , e : Int ): Repr = v.shiftLeft(e)
356
+ @ inline def multiplyBy10Pow (v : Repr , e : Int ): Repr = v.multiply(BigInteger .TEN .pow(e))
357
+
358
+ @ inline def compare (x : Repr , y : Repr ): Int = x.compareTo(y)
359
+ }
360
+ }
301
361
302
362
private def parseFloatHexadecimal (integralPartStr : String ,
303
363
fractionalPartStr : String , binaryExpStr : String ): scala.Float = {
0 commit comments