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
18
+ import scala .scalajs .LinkingInfo ._
19
19
20
20
/* This is a hijacked class. Its instances are primitive numbers.
21
21
* Constructors are not emitted.
@@ -226,9 +226,23 @@ object Float {
226
226
fractionalPartStr : String , exponentStr : String ,
227
227
zDown : scala.Float , zUp : scala.Float , mid : scala.Double ): scala.Float = {
228
228
229
+ /* Get the best available implementation of big integers for the given platform.
230
+ *
231
+ * If JS bigint's are supported, use them. Otherwise fall back on
232
+ * `java.math.BigInteger`.
233
+ *
234
+ * We need a `linkTimeIf` here because the JS bigint implementation uses
235
+ * the `**` operator, which does not link when `esVersion < ESVersion.ES2016`.
236
+ */
237
+ val bigIntImpl = linkTimeIf[BigIntImpl ](esVersion >= ESVersion .ES2020 ) {
238
+ BigIntImpl .JSBigInt
239
+ } {
240
+ BigIntImpl .JBigInteger
241
+ }
242
+
229
243
// 1. Accurately parse the string with the representation f × 10ᵉ
230
244
231
- val f : BigInteger = new BigInteger (integralPartStr + fractionalPartStr)
245
+ val f : bigIntImpl. Repr = bigIntImpl.fromString (integralPartStr + fractionalPartStr)
232
246
val e : Int = Integer .parseInt(exponentStr) - fractionalPartStr.length()
233
247
234
248
/* Note: we know that `e` is "reasonable" (in the range [-324, +308]). If
@@ -261,24 +275,23 @@ object Float {
261
275
262
276
val mExplicitBits = midBits & ((1L << mbits) - 1 )
263
277
val mImplicit1Bit = 1L << mbits // the implicit '1' bit of a normalized floating-point number
264
- val m = BigInteger .valueOf (mExplicitBits | mImplicit1Bit)
278
+ val m = bigIntImpl.fromUnsignedLong53 (mExplicitBits | mImplicit1Bit)
265
279
val k = biasedK - bias - mbits
266
280
267
281
// 3. Accurately compare f × 10ᵉ to m × 2ᵏ
268
282
269
- @ inline def compare (x : BigInteger , y : BigInteger ): Int =
270
- x.compareTo(y)
283
+ import bigIntImpl .{multiplyBy2Pow , multiplyBy10Pow }
271
284
272
285
val cmp = if (e >= 0 ) {
273
286
if (k >= 0 )
274
- compare(multiplyBy10Pow(f, e), multiplyBy2Pow(m, k))
287
+ bigIntImpl. compare(multiplyBy10Pow(f, e), multiplyBy2Pow(m, k))
275
288
else
276
- compare(multiplyBy2Pow(multiplyBy10Pow(f, e), - k), m) // this branch may be dead code in practice
289
+ bigIntImpl. compare(multiplyBy2Pow(multiplyBy10Pow(f, e), - k), m) // this branch may be dead code in practice
277
290
} else {
278
291
if (k >= 0 )
279
- compare(f, multiplyBy2Pow(multiplyBy10Pow(m, - e), k))
292
+ bigIntImpl. compare(f, multiplyBy2Pow(multiplyBy10Pow(m, - e), k))
280
293
else
281
- compare(multiplyBy2Pow(f, - k), multiplyBy10Pow(m, - e))
294
+ bigIntImpl. compare(multiplyBy2Pow(f, - k), multiplyBy10Pow(m, - e))
282
295
}
283
296
284
297
// 4. Choose zDown or zUp depending on the result of the comparison
@@ -293,11 +306,54 @@ object Float {
293
306
zUp
294
307
}
295
308
296
- @ inline private def multiplyBy10Pow (v : BigInteger , e : Int ): BigInteger =
297
- v.multiply(BigInteger .TEN .pow(e))
309
+ /** An implementation of big integer arithmetics that we need in the above method. */
310
+ private sealed abstract class BigIntImpl {
311
+ type Repr
312
+
313
+ def fromString (str : String ): Repr
314
+
315
+ /** Creates a big integer from a `Long` that needs at most 53 bits (unsigned). */
316
+ def fromUnsignedLong53 (x : scala.Long ): Repr
317
+
318
+ def multiplyBy2Pow (v : Repr , e : Int ): Repr
319
+ def multiplyBy10Pow (v : Repr , e : Int ): Repr
320
+
321
+ def compare (x : Repr , y : Repr ): Int
322
+ }
323
+
324
+ private object BigIntImpl {
325
+ object JSBigInt extends BigIntImpl {
326
+ type Repr = js.BigInt
327
+
328
+ @ inline def fromString (str : String ): Repr = js.BigInt (str)
298
329
299
- @ inline private def multiplyBy2Pow (v : BigInteger , e : Int ): BigInteger =
300
- v.shiftLeft(e)
330
+ // The 53-bit restriction guarantees that the conversion to `Double` is lossless.
331
+ @ inline def fromUnsignedLong53 (x : scala.Long ): Repr = js.BigInt (x.toDouble)
332
+
333
+ @ inline def multiplyBy2Pow (v : Repr , e : Int ): Repr = v << js.BigInt (e)
334
+ @ inline def multiplyBy10Pow (v : Repr , e : Int ): Repr = v * (js.BigInt (10 ) ** js.BigInt (e))
335
+
336
+ @ inline def compare (x : Repr , y : Repr ): Int = {
337
+ if (x < y) - 1
338
+ else if (x > y) 1
339
+ else 0
340
+ }
341
+ }
342
+
343
+ object JBigInteger extends BigIntImpl {
344
+ import java .math .BigInteger
<
67ED
td data-grid-cell-id="diff-bac3ba881ae5c65c4db1a2daaab7bbe0b539b09911076b5df246d5fa3a9c4231-300-345-0" data-selected="false" role="gridcell" style="background-color:var(--diffBlob-additionNum-bgColor, var(--diffBlob-addition-bgColor-num));text-align:center" tabindex="-1" valign="top" class="focusable-grid-cell diff-line-number position-relative left-side">
345
+
346
+ type Repr = BigInteger
347
+
348
+ @ inline def fromString (str : String ): Repr = new BigInteger (str)
349
+ @ inline def fromUnsignedLong53 (x : scala.Long ): Repr = BigInteger .valueOf(x)
350
+
351
+ @ inline def multiplyBy2Pow (v : Repr , e : Int ): Repr = v.shiftLeft(e)
352
+ @ inline def multiplyBy10Pow (v : Repr , e : Int ): Repr = v.multiply(BigInteger .TEN .pow(e))
353
+
354
+ @ inline def compare (x : Repr , y : Repr ): Int = x.compareTo(y)
355
+ }
356
+ }
301
357
302
358
private def parseFloatHexadecimal (integralPartStr : String ,
303
359
fractionalPartStr : String , binaryExpStr : String ): scala.Float = {
0 commit comments