@grain/stdlib 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/array.gr +61 -1
  3. package/array.md +113 -0
  4. package/bigint.md +30 -30
  5. package/buffer.gr +24 -22
  6. package/char.gr +2 -2
  7. package/float32.md +3 -3
  8. package/float64.md +3 -3
  9. package/immutablemap.gr +493 -0
  10. package/immutablemap.md +479 -0
  11. package/immutablepriorityqueue.gr +360 -0
  12. package/immutablepriorityqueue.md +291 -0
  13. package/immutableset.gr +498 -0
  14. package/immutableset.md +449 -0
  15. package/list.gr +75 -2
  16. package/list.md +110 -0
  17. package/map.gr +1 -2
  18. package/marshal.gr +1058 -0
  19. package/marshal.md +76 -0
  20. package/number.gr +689 -23
  21. package/number.md +362 -27
  22. package/package.json +1 -1
  23. package/pervasives.gr +16 -5
  24. package/pervasives.md +28 -0
  25. package/priorityqueue.gr +261 -0
  26. package/priorityqueue.md +309 -0
  27. package/queue.gr +14 -1
  28. package/queue.md +16 -1
  29. package/regex.gr +90 -67
  30. package/runtime/bigint.gr +4 -4
  31. package/runtime/compare.gr +179 -0
  32. package/runtime/compare.md +6 -0
  33. package/runtime/equal.gr +3 -3
  34. package/runtime/exception.gr +9 -5
  35. package/runtime/exception.md +8 -2
  36. package/runtime/gc.gr +2 -1
  37. package/runtime/malloc.gr +1 -3
  38. package/runtime/numberUtils.gr +11 -11
  39. package/runtime/numbers.gr +423 -100
  40. package/runtime/numbers.md +50 -0
  41. package/runtime/string.gr +4 -2
  42. package/set.gr +26 -27
  43. package/stack.gr +12 -0
  44. package/stack.md +15 -0
  45. package/string.gr +409 -53
  46. package/string.md +164 -1
  47. package/sys/file.gr +4 -4
  48. package/sys/file.md +3 -3
  49. package/sys/process.gr +3 -3
  50. package/sys/process.md +3 -3
  51. package/sys/random.gr +2 -2
  52. package/sys/random.md +2 -2
  53. package/sys/time.gr +2 -2
  54. package/sys/time.md +2 -2
@@ -20,6 +20,7 @@ primitive (||): (Bool, Bool) -> Bool = "@or"
20
20
  primitive throw: Exception -> a = "@throw"
21
21
 
22
22
  exception UnknownNumberTag
23
+ exception InvariantViolation
23
24
 
24
25
  import {
25
26
  newRational,
@@ -78,7 +79,29 @@ export let isFloat = x => {
78
79
  if (isBoxedNumber(x)) {
79
80
  let tag = WasmI32.load(x, 4n)
80
81
  WasmI32.eq(tag, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) ||
81
- WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
82
+ WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
83
+ } else {
84
+ false
85
+ }
86
+ }
87
+
88
+ @unsafe
89
+ export let isInteger = x => {
90
+ if (isBoxedNumber(x)) {
91
+ let tag = WasmI32.load(x, 4n)
92
+ WasmI32.eq(tag, Tags._GRAIN_INT32_BOXED_NUM_TAG) ||
93
+ WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG) ||
94
+ WasmI32.eq(tag, Tags._GRAIN_BIGINT_BOXED_NUM_TAG)
95
+ } else {
96
+ true
97
+ }
98
+ }
99
+
100
+ @unsafe
101
+ export let isRational = x => {
102
+ if (isBoxedNumber(x)) {
103
+ let tag = WasmI32.load(x, 4n)
104
+ WasmI32.eq(tag, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG)
82
105
  } else {
83
106
  false
84
107
  }
@@ -495,13 +518,13 @@ let isIntegerF64 = value => {
495
518
  @unsafe
496
519
  let isSafeIntegerF32 = value => {
497
520
  WasmF32.le(WasmF32.abs(value), _F32_MAX_SAFE_INTEGER) &&
498
- WasmF32.eq(WasmF32.trunc(value), value)
521
+ WasmF32.eq(WasmF32.trunc(value), value)
499
522
  }
500
523
 
501
524
  @unsafe
502
525
  let isSafeIntegerF64 = value => {
503
526
  WasmF64.le(WasmF64.abs(value), _F64_MAX_SAFE_INTEGER) &&
504
- WasmF64.eq(WasmF64.trunc(value), value)
527
+ WasmF64.eq(WasmF64.trunc(value), value)
505
528
  }
506
529
 
507
530
  /** Number-aware equality checking
@@ -541,12 +564,12 @@ let numberEqualSimpleHelp = (x, y) => {
541
564
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
542
565
  let yBoxedVal = boxedFloat32Number(y)
543
566
  isSafeIntegerF32(yBoxedVal) &&
544
- WasmF32.eq(WasmF32.convertI32S(xval), yBoxedVal)
567
+ WasmF32.eq(WasmF32.convertI32S(xval), yBoxedVal)
545
568
  },
546
569
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
547
570
  let yBoxedVal = boxedFloat64Number(y)
548
571
  isSafeIntegerF64(yBoxedVal) &&
549
- WasmF64.eq(WasmF64.convertI32S(xval), yBoxedVal)
572
+ WasmF64.eq(WasmF64.convertI32S(xval), yBoxedVal)
550
573
  },
551
574
  _ => {
552
575
  throw UnknownNumberTag
@@ -583,12 +606,12 @@ let numberEqualInt64Help = (xBoxedVal, y) => {
583
606
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
584
607
  let yBoxedVal = boxedFloat32Number(y)
585
608
  isSafeIntegerF32(yBoxedVal) &&
586
- WasmI64.eq(xBoxedVal, WasmI64.truncF32S(yBoxedVal))
609
+ WasmI64.eq(xBoxedVal, WasmI64.truncF32S(yBoxedVal))
587
610
  },
588
611
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
589
612
  let yBoxedVal = boxedFloat64Number(y)
590
613
  isSafeIntegerF64(yBoxedVal) &&
591
- WasmI64.eq(xBoxedVal, WasmI64.truncF64S(yBoxedVal))
614
+ WasmI64.eq(xBoxedVal, WasmI64.truncF64S(yBoxedVal))
592
615
  },
593
616
  _ => {
594
617
  throw UnknownNumberTag
@@ -635,7 +658,7 @@ let numberEqualRationalHelp = (xptr, y) => {
635
658
  BI.toFloat32(xNumerator),
636
659
  BI.toFloat32(xDenominator)
637
660
  )
638
- // TODO: (#303) maybe we should have some sort of tolerance?
661
+ // TODO(#303): maybe we should have some sort of tolerance?
639
662
  WasmF32.eq(xAsFloat, yBoxedVal)
640
663
  },
641
664
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
@@ -644,7 +667,7 @@ let numberEqualRationalHelp = (xptr, y) => {
644
667
  BI.toFloat64(xNumerator),
645
668
  BI.toFloat64(xDenominator)
646
669
  )
647
- // TODO: (#303) maybe we should have some sort of tolerance?
670
+ // TODO(#303): maybe we should have some sort of tolerance?
648
671
  WasmF64.eq(xAsFloat, yBoxedVal)
649
672
  },
650
673
  _ => {
@@ -686,12 +709,12 @@ let numberEqualFloat64Help = (x, y) => {
686
709
  },
687
710
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
688
711
  let yBoxedVal = boxedFloat32Number(y)
689
- // TODO: (#303) maybe we should have some sort of tolerance?
712
+ // TODO(#303): maybe we should have some sort of tolerance?
690
713
  WasmF64.eq(x, WasmF64.promoteF32(yBoxedVal))
691
714
  },
692
715
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
693
716
  let yBoxedVal = boxedFloat64Number(y)
694
- // TODO: (#303) maybe we should have some sort of tolerance?
717
+ // TODO(#303): maybe we should have some sort of tolerance?
695
718
  WasmF64.eq(x, yBoxedVal)
696
719
  },
697
720
  _ => {
@@ -820,14 +843,16 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
820
843
  t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
821
844
  let xval = WasmI64.extendI32S(xval)
822
845
  let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
823
- let result = if (isSub) WasmI64.sub(xval, yBoxedVal)
846
+ let result =
847
+ if (isSub) WasmI64.sub(xval, yBoxedVal)
824
848
  else WasmI64.add(xval, yBoxedVal)
825
849
  reducedInteger(result)
826
850
  },
827
851
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
828
852
  let yBoxedVal = boxedInt64Number(y)
829
853
  let xval64 = WasmI64.extendI32S(xval)
830
- let result = if (isSub) WasmI64.sub(xval64, yBoxedVal)
854
+ let result =
855
+ if (isSub) WasmI64.sub(xval64, yBoxedVal)
831
856
  else WasmI64.add(xval64, yBoxedVal)
832
857
  if (
833
858
  WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64) ||
@@ -861,7 +886,8 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
861
886
  let yDenominator = boxedRationalDenominator(y)
862
887
  let expandedXNumerator = BI.mul(xBig, yDenominator)
863
888
  Memory.decRef(xBig)
864
- let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
889
+ let result =
890
+ if (isSub) BI.sub(expandedXNumerator, yNumerator)
865
891
  else BI.add(expandedXNumerator, yNumerator)
866
892
  let ret = reducedFractionBigInt(result, yDenominator)
867
893
  Memory.decRef(expandedXNumerator)
@@ -871,15 +897,16 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
871
897
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
872
898
  let yBoxedVal = boxedFloat32Number(y)
873
899
  let xval = WasmF32.convertI32S(xval)
874
- let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
900
+ let result =
901
+ if (isSub) WasmF32.sub(xval, yBoxedVal)
875
902
  else WasmF32.add(xval, yBoxedVal)
876
- // TODO: (#304) is this safe?
877
903
  newFloat32(result)
878
904
  },
879
905
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
880
906
  let yBoxedVal = boxedFloat64Number(y)
881
907
  let xval = WasmF64.convertI32S(xval)
882
- let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
908
+ let result =
909
+ if (isSub) WasmF64.sub(xval, yBoxedVal)
883
910
  else WasmF64.add(xval, yBoxedVal)
884
911
  newFloat64(result)
885
912
  },
@@ -918,14 +945,16 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
918
945
  match (yBoxedNumberTag) {
919
946
  t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
920
947
  let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
921
- let result = if (isSub) WasmI64.sub(xval, yBoxedVal)
948
+ let result =
949
+ if (isSub) WasmI64.sub(xval, yBoxedVal)
922
950
  else WasmI64.add(xval, yBoxedVal)
923
951
  reducedInteger(result)
924
952
  },
925
953
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
926
954
  let yBoxedVal = boxedInt64Number(y)
927
955
  let xval64 = xval
928
- let result = if (isSub) WasmI64.sub(xval64, yBoxedVal)
956
+ let result =
957
+ if (isSub) WasmI64.sub(xval64, yBoxedVal)
929
958
  else WasmI64.add(xval64, yBoxedVal)
930
959
  if (
931
960
  WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64) ||
@@ -959,7 +988,8 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
959
988
  let yDenominator = boxedRationalDenominator(y)
960
989
  let expandedXNumerator = BI.mul(xBig, yDenominator)
961
990
  Memory.decRef(xBig)
962
- let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
991
+ let result =
992
+ if (isSub) BI.sub(expandedXNumerator, yNumerator)
963
993
  else BI.add(expandedXNumerator, yNumerator)
964
994
  let ret = reducedFractionBigInt(result, yDenominator)
965
995
  Memory.decRef(expandedXNumerator)
@@ -969,15 +999,16 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
969
999
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
970
1000
  let xval = WasmF32.convertI64S(xval)
971
1001
  let yBoxedVal = boxedFloat32Number(y)
972
- let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
1002
+ let result =
1003
+ if (isSub) WasmF32.sub(xval, yBoxedVal)
973
1004
  else WasmF32.add(xval, yBoxedVal)
974
- // TODO(#304): this isn't safe enough
975
1005
  newFloat32(result)
976
1006
  },
977
1007
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
978
1008
  let xval = WasmF64.convertI64S(xval)
979
1009
  let yBoxedVal = boxedFloat64Number(y)
980
- let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
1010
+ let result =
1011
+ if (isSub) WasmF64.sub(xval, yBoxedVal)
981
1012
  else WasmF64.add(xval, yBoxedVal)
982
1013
  newFloat64(result)
983
1014
  },
@@ -1071,7 +1102,8 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
1071
1102
  let yNumerator = boxedRationalNumerator(y)
1072
1103
  let yDenominator = boxedRationalDenominator(y)
1073
1104
  let expandedXNumerator = BI.mul(x, yDenominator)
1074
- let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
1105
+ let result =
1106
+ if (isSub) BI.sub(expandedXNumerator, yNumerator)
1075
1107
  else BI.add(expandedXNumerator, yNumerator)
1076
1108
  Memory.decRef(expandedXNumerator)
1077
1109
  let ret = reducedFractionBigInt(result, yDenominator)
@@ -1081,15 +1113,16 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
1081
1113
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1082
1114
  let xval = BI.toFloat32(x)
1083
1115
  let yBoxedVal = boxedFloat32Number(y)
1084
- let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
1116
+ let result =
1117
+ if (isSub) WasmF32.sub(xval, yBoxedVal)
1085
1118
  else WasmF32.add(xval, yBoxedVal)
1086
- // TODO: (#304) this isn't safe enough
1087
1119
  newFloat32(result)
1088
1120
  },
1089
1121
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1090
1122
  let xval = BI.toFloat64(x)
1091
1123
  let yBoxedVal = boxedFloat64Number(y)
1092
- let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
1124
+ let result =
1125
+ if (isSub) WasmF64.sub(xval, yBoxedVal)
1093
1126
  else WasmF64.add(xval, yBoxedVal)
1094
1127
  newFloat64(result)
1095
1128
  },
@@ -1108,7 +1141,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1108
1141
  let yval = untagSimple(y)
1109
1142
  let yBig = BI.makeWrappedInt32(yval)
1110
1143
  let expandedYNumerator = BI.mul(xDenominator, yBig)
1111
- let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1144
+ let result =
1145
+ if (isSub) BI.sub(xNumerator, expandedYNumerator)
1112
1146
  else BI.add(xNumerator, expandedYNumerator)
1113
1147
  Memory.decRef(expandedYNumerator)
1114
1148
  Memory.decRef(yBig)
@@ -1125,7 +1159,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1125
1159
  let yNumerator = boxedRationalNumerator(y)
1126
1160
  let yDenominator = boxedRationalDenominator(y)
1127
1161
  if (BI.eq(xDenominator, yDenominator)) {
1128
- let newNumerator = if (isSub) BI.sub(xNumerator, yNumerator)
1162
+ let newNumerator =
1163
+ if (isSub) BI.sub(xNumerator, yNumerator)
1129
1164
  else BI.add(xNumerator, yNumerator)
1130
1165
  let ret = reducedFractionBigInt(newNumerator, xDenominator)
1131
1166
  Memory.decRef(newNumerator)
@@ -1133,7 +1168,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1133
1168
  } else {
1134
1169
  let numerator1 = BI.mul(xNumerator, yDenominator)
1135
1170
  let numerator2 = BI.mul(yNumerator, xDenominator)
1136
- let numerator = if (isSub) BI.sub(numerator1, numerator2)
1171
+ let numerator =
1172
+ if (isSub) BI.sub(numerator1, numerator2)
1137
1173
  else BI.add(numerator1, numerator2)
1138
1174
  let denominator = BI.mul(xDenominator, yDenominator)
1139
1175
  let ret = reducedFractionBigInt(numerator, denominator)
@@ -1147,7 +1183,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1147
1183
  let yBig = BI.makeWrappedInt32(boxedInt32Number(y))
1148
1184
  let expandedYNumerator = BI.mul(yBig, xDenominator)
1149
1185
  Memory.decRef(yBig)
1150
- let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1186
+ let result =
1187
+ if (isSub) BI.sub(xNumerator, expandedYNumerator)
1151
1188
  else BI.add(xNumerator, expandedYNumerator)
1152
1189
  let ret = reducedFractionBigInt(result, xDenominator)
1153
1190
  Memory.decRef(expandedYNumerator)
@@ -1158,7 +1195,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1158
1195
  let yBig = BI.makeWrappedInt64(boxedInt64Number(y))
1159
1196
  let expandedYNumerator = BI.mul(yBig, xDenominator)
1160
1197
  Memory.decRef(yBig)
1161
- let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1198
+ let result =
1199
+ if (isSub) BI.sub(xNumerator, expandedYNumerator)
1162
1200
  else BI.add(xNumerator, expandedYNumerator)
1163
1201
  let ret = reducedFractionBigInt(result, xDenominator)
1164
1202
  Memory.decRef(expandedYNumerator)
@@ -1167,7 +1205,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1167
1205
  },
1168
1206
  t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1169
1207
  let expandedYNumerator = BI.mul(xDenominator, y)
1170
- let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1208
+ let result =
1209
+ if (isSub) BI.sub(xNumerator, expandedYNumerator)
1171
1210
  else BI.add(xNumerator, expandedYNumerator)
1172
1211
  Memory.decRef(expandedYNumerator)
1173
1212
  let ret = reducedFractionBigInt(result, xDenominator)
@@ -1179,7 +1218,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1179
1218
  BI.toFloat32(xNumerator),
1180
1219
  BI.toFloat32(xDenominator)
1181
1220
  )
1182
- let result = if (isSub) WasmF32.sub(xval, boxedFloat32Number(y))
1221
+ let result =
1222
+ if (isSub) WasmF32.sub(xval, boxedFloat32Number(y))
1183
1223
  else WasmF32.add(xval, boxedFloat32Number(y))
1184
1224
  newFloat32(result)
1185
1225
  },
@@ -1188,8 +1228,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1188
1228
  let xdenfloat = BI.toFloat64(xDenominator)
1189
1229
  let xval = WasmF64.div(xnumfloat, xdenfloat)
1190
1230
  let yval = boxedFloat64Number(y)
1191
- let result = if (isSub) WasmF64.sub(xval, yval)
1192
- else WasmF64.add(xval, yval)
1231
+ let result =
1232
+ if (isSub) WasmF64.sub(xval, yval) else WasmF64.add(xval, yval)
1193
1233
  let ret = newFloat64(result)
1194
1234
  ret
1195
1235
  },
@@ -1326,7 +1366,6 @@ let numberTimesDivideInt64Help = (xval, y, isDivide) => {
1326
1366
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1327
1367
  let xval = WasmF32.convertI64S(xval)
1328
1368
  let yBoxedVal = boxedFloat32Number(y)
1329
- // TODO: (#304) is this safe?
1330
1369
  if (isDivide) {
1331
1370
  newFloat32(WasmF32.div(xval, yBoxedVal))
1332
1371
  } else {
@@ -1385,6 +1424,13 @@ let numberTimesDivideBigIntHelp = (x, y, isDivide) => {
1385
1424
  Memory.decRef(yBig)
1386
1425
  ret
1387
1426
  },
1427
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1428
+ if (isDivide) {
1429
+ reducedBigInteger(BI.div(x, y))
1430
+ } else {
1431
+ reducedBigInteger(BI.mul(x, y))
1432
+ }
1433
+ },
1388
1434
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1389
1435
  let yNumerator = boxedRationalNumerator(y)
1390
1436
  let yDenominator = boxedRationalDenominator(y)
@@ -1407,7 +1453,6 @@ let numberTimesDivideBigIntHelp = (x, y, isDivide) => {
1407
1453
  // we can only fit rather small bigints (<4 limbs) into an F32
1408
1454
  let xval = BI.toFloat64(x)
1409
1455
  let yBoxedVal = WasmF64.promoteF32(boxedFloat32Number(y))
1410
- // TODO: (#304) is this safe?
1411
1456
  if (isDivide) {
1412
1457
  newFloat64(WasmF64.div(xval, yBoxedVal))
1413
1458
  } else {
@@ -1530,10 +1575,11 @@ let numberTimesDivideRationalHelp = (x, y, isDivide) => {
1530
1575
  let yDenominator = boxedRationalDenominator(y)
1531
1576
  // (a / b) * (c / d) == (a * c) / (b * d)
1532
1577
  // (a / b) / (c / d) == (a * d) / (b * c)
1533
- // TODO: (#304) this could maybe be written in a more overflow-proof way
1534
- let numerator = if (isDivide) BI.mul(xNumerator, yDenominator)
1578
+ let numerator =
1579
+ if (isDivide) BI.mul(xNumerator, yDenominator)
1535
1580
  else BI.mul(xNumerator, yNumerator)
1536
- let denominator = if (isDivide) BI.mul(xDenominator, yNumerator)
1581
+ let denominator =
1582
+ if (isDivide) BI.mul(xDenominator, yNumerator)
1537
1583
  else BI.mul(xDenominator, yDenominator)
1538
1584
  reducedFractionBigInt(numerator, denominator)
1539
1585
  },
@@ -1669,7 +1715,8 @@ let numberMod = (x, y) => {
1669
1715
  WasmI64.gtS(xval, 0N) && WasmI64.ltS(yval, 0N)
1670
1716
  ) {
1671
1717
  let modval = WasmI64.remS(i64abs(xval), i64abs(yval))
1672
- let result = if (WasmI64.ne(modval, 0N))
1718
+ let result =
1719
+ if (WasmI64.ne(modval, 0N))
1673
1720
  WasmI64.mul(
1674
1721
  WasmI64.sub(i64abs(yval), modval),
1675
1722
  if (WasmI64.ltS(yval, 0N)) -1N else 1N
@@ -1681,9 +1728,18 @@ let numberMod = (x, y) => {
1681
1728
  }
1682
1729
 
1683
1730
  /*
1684
- * ===== LESS THAN / GREATER THAN / LESS EQUAL / GREATER EQUAL =====
1685
- * Coerce to float64 and then do comparisons
1686
- * TODO: (#305) Could probably be made more efficient
1731
+ * ===== COMPARISONS =====
1732
+ * Int/int and float/float comparisons are always accurate.
1733
+ * Rational/rational comparisons are approximations with the exception of
1734
+ * equality, which is always accurate.
1735
+ *
1736
+ * Values compared to floats or rationals are first converted to floats.
1737
+ *
1738
+ * All comparison operators consider NaN not equal to, less than, or greater
1739
+ * than NaN, with the exception of `compare`, which considers NaN equal to
1740
+ * itself and otherwise smaller than any other float value. This provides a
1741
+ * total order (https://en.wikipedia.org/wiki/Total_order) over all numerical
1742
+ * values, making `compare` suitable for sorting or ordering.
1687
1743
  */
1688
1744
 
1689
1745
  @unsafe
@@ -1721,81 +1777,286 @@ let cmpBigInt = (x: WasmI32, y: WasmI32) => {
1721
1777
  }
1722
1778
  }
1723
1779
 
1724
- // TODO: (#305) is this safe? I think it's safe?
1725
1780
  @unsafe
1726
- export let (<) = (x: Number, y: Number) => {
1727
- let xw32 = WasmI32.fromGrain(x)
1728
- let yw32 = WasmI32.fromGrain(y)
1729
- if (isBigInt(xw32)) {
1730
- WasmI32.ltS(cmpBigInt(xw32, yw32), 0n)
1731
- } else if (isBigInt(yw32)) {
1732
- WasmI32.geS(cmpBigInt(yw32, xw32), 0n)
1781
+ let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
1782
+ let xf = if (is64) {
1783
+ boxedFloat64Number(x)
1733
1784
  } else {
1734
- let xval = coerceNumberToWasmF64(x)
1735
- let yval = coerceNumberToWasmF64(y)
1736
- WasmF64.lt(xval, yval)
1785
+ WasmF64.promoteF32(boxedFloat32Number(x))
1786
+ }
1787
+ if (isSimpleNumber(y)) {
1788
+ let yf = WasmF64.convertI32S(untagSimple(y))
1789
+ // special NaN cases
1790
+ if (totalOrdering && WasmF64.ne(xf, xf)) {
1791
+ if (WasmF64.ne(yf, yf)) {
1792
+ 0n
1793
+ } else {
1794
+ -1n
1795
+ }
1796
+ } else if (totalOrdering && WasmF64.ne(yf, yf)) {
1797
+ if (WasmF64.ne(xf, xf)) {
1798
+ 0n
1799
+ } else {
1800
+ 1n
1801
+ }
1802
+ } else {
1803
+ if (WasmF64.lt(xf, yf)) -1n else if (WasmF64.gt(xf, yf)) 1n else 0n
1804
+ }
1805
+ } else {
1806
+ let yBoxedNumberTag = boxedNumberTag(y)
1807
+ if (yBoxedNumberTag == Tags._GRAIN_BIGINT_BOXED_NUM_TAG) {
1808
+ WasmI32.sub(0n, cmpBigInt(y, x))
1809
+ } else {
1810
+ let yf = match (yBoxedNumberTag) {
1811
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1812
+ WasmF64.convertI32S(boxedInt32Number(y))
1813
+ },
1814
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1815
+ WasmF64.convertI64S(boxedInt64Number(y))
1816
+ },
1817
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1818
+ throw InvariantViolation
1819
+ },
1820
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1821
+ WasmF64.div(
1822
+ BI.toFloat64(boxedRationalNumerator(y)),
1823
+ BI.toFloat64(boxedRationalDenominator(y))
1824
+ )
1825
+ },
1826
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1827
+ WasmF64.promoteF32(boxedFloat32Number(y))
1828
+ },
1829
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1830
+ boxedFloat64Number(y)
1831
+ },
1832
+ _ => {
1833
+ throw UnknownNumberTag
1834
+ },
1835
+ }
1836
+ // special NaN cases
1837
+ if (totalOrdering && WasmF64.ne(xf, xf)) {
1838
+ if (WasmF64.ne(yf, yf)) {
1839
+ 0n
1840
+ } else {
1841
+ -1n
1842
+ }
1843
+ } else if (totalOrdering && WasmF64.ne(yf, yf)) {
1844
+ if (WasmF64.ne(xf, xf)) {
1845
+ 0n
1846
+ } else {
1847
+ 1n
1848
+ }
1849
+ } else {
1850
+ if (WasmF64.lt(xf, yf)) -1n else if (WasmF64.gt(xf, yf)) 1n else 0n
1851
+ }
1852
+ }
1737
1853
  }
1738
1854
  }
1739
1855
 
1740
1856
  @unsafe
1741
- export let (>) = (x: Number, y: Number) => {
1742
- let xw32 = WasmI32.fromGrain(x)
1743
- let yw32 = WasmI32.fromGrain(y)
1744
- if (isBigInt(xw32)) {
1745
- WasmI32.gtS(cmpBigInt(xw32, yw32), 0n)
1746
- } else if (isBigInt(yw32)) {
1747
- WasmI32.leS(cmpBigInt(yw32, xw32), 0n)
1857
+ let cmpSmallInt = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
1858
+ let xi = if (is64) {
1859
+ boxedInt64Number(x)
1748
1860
  } else {
1749
- let xval = coerceNumberToWasmF64(x)
1750
- let yval = coerceNumberToWasmF64(y)
1751
- WasmF64.gt(xval, yval)
1861
+ WasmI64.extendI32S(boxedInt32Number(x))
1862
+ }
1863
+ if (isSimpleNumber(y)) {
1864
+ let yi = WasmI64.extendI32S(untagSimple(y))
1865
+ if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
1866
+ } else {
1867
+ let yBoxedNumberTag = boxedNumberTag(y)
1868
+ match (yBoxedNumberTag) {
1869
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1870
+ let yi = WasmI64.extendI32S(boxedInt32Number(y))
1871
+ if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
1872
+ },
1873
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1874
+ let yi = boxedInt64Number(y)
1875
+ if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
1876
+ },
1877
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1878
+ WasmI32.sub(0n, cmpBigInt(y, x))
1879
+ },
1880
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1881
+ // Rationals and ints are never considered equal
1882
+ if (
1883
+ WasmF64.lt(
1884
+ WasmF64.convertI64S(xi),
1885
+ WasmF64.div(
1886
+ BI.toFloat64(boxedRationalNumerator(y)),
1887
+ BI.toFloat64(boxedRationalDenominator(y))
1888
+ )
1889
+ )
1890
+ ) -1n else 1n
1891
+ },
1892
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1893
+ WasmI32.sub(0n, cmpFloat(y, x, false, totalOrdering))
1894
+ },
1895
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1896
+ WasmI32.sub(0n, cmpFloat(y, x, true, totalOrdering))
1897
+ },
1898
+ _ => {
1899
+ throw UnknownNumberTag
1900
+ },
1901
+ }
1752
1902
  }
1753
1903
  }
1754
1904
 
1755
1905
  @unsafe
1756
- export let (<=) = (x: Number, y: Number) => {
1757
- let xw32 = WasmI32.fromGrain(x)
1758
- let yw32 = WasmI32.fromGrain(y)
1759
- if (isBigInt(xw32)) {
1760
- WasmI32.leS(cmpBigInt(xw32, yw32), 0n)
1761
- } else if (isBigInt(yw32)) {
1762
- WasmI32.geS(cmpBigInt(yw32, xw32), 0n)
1906
+ let cmpRational = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
1907
+ if (isSimpleNumber(y)) {
1908
+ let xf = WasmF64.div(
1909
+ BI.toFloat64(boxedRationalNumerator(x)),
1910
+ BI.toFloat64(boxedRationalDenominator(x))
1911
+ )
1912
+ // Rationals and ints are never considered equal
1913
+ if (WasmF64.lt(xf, WasmF64.convertI32S(untagSimple(y)))) -1n else 1n
1763
1914
  } else {
1764
- // Equality is finicky, so delegate
1765
- let xval = coerceNumberToWasmF64(x)
1766
- let yval = coerceNumberToWasmF64(y)
1767
- if (WasmF64.lt(xval, yval)) {
1768
- true
1769
- } else {
1770
- let x = WasmI32.fromGrain(x)
1771
- let y = WasmI32.fromGrain(y)
1772
- numberEqual(x, y)
1915
+ let yBoxedNumberTag = boxedNumberTag(y)
1916
+ match (yBoxedNumberTag) {
1917
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1918
+ WasmI32.sub(0n, cmpSmallInt(y, x, false, totalOrdering))
1919
+ },
1920
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1921
+ WasmI32.sub(0n, cmpSmallInt(y, x, true, totalOrdering))
1922
+ },
1923
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1924
+ WasmI32.sub(0n, cmpBigInt(y, x))
1925
+ },
1926
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1927
+ // Comparing rationals efficiently is an open problem
1928
+ // Producing a definitive answer is quite expensive, so if the two
1929
+ // values are not strictly equal we approximate an answer
1930
+
1931
+ let xNumerator = boxedRationalNumerator(x)
1932
+ let xDenominator = boxedRationalDenominator(x)
1933
+ let yNumerator = boxedRationalNumerator(y)
1934
+ let yDenominator = boxedRationalDenominator(y)
1935
+
1936
+ if (
1937
+ BI.cmp(xNumerator, yNumerator) == 0n &&
1938
+ BI.cmp(xDenominator, yDenominator) == 0n
1939
+ ) {
1940
+ 0n
1941
+ } else {
1942
+ let xf = WasmF64.div(
1943
+ BI.toFloat64(xNumerator),
1944
+ BI.toFloat64(xDenominator)
1945
+ )
1946
+ let yf = WasmF64.div(
1947
+ BI.toFloat64(yNumerator),
1948
+ BI.toFloat64(yDenominator)
1949
+ )
1950
+ if (WasmF64.lt(xf, yf)) -1n else 1n
1951
+ }
1952
+ },
1953
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1954
+ WasmI32.sub(0n, cmpFloat(y, x, false, totalOrdering))
1955
+ },
1956
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1957
+ WasmI32.sub(0n, cmpFloat(y, x, true, totalOrdering))
1958
+ },
1959
+ _ => {
1960
+ throw UnknownNumberTag
1961
+ },
1773
1962
  }
1774
1963
  }
1775
1964
  }
1776
1965
 
1777
1966
  @unsafe
1778
- export let (>=) = (x: Number, y: Number) => {
1779
- let xw32 = WasmI32.fromGrain(x)
1780
- let yw32 = WasmI32.fromGrain(y)
1781
- if (isBigInt(xw32)) {
1782
- WasmI32.leS(cmpBigInt(xw32, yw32), 0n)
1783
- } else if (isBigInt(yw32)) {
1784
- WasmI32.geS(cmpBigInt(yw32, xw32), 0n)
1785
- } else {
1786
- // Equality is finicky, so delegate
1787
- let xval = coerceNumberToWasmF64(x)
1788
- let yval = coerceNumberToWasmF64(y)
1789
- if (WasmF64.gt(xval, yval)) {
1790
- true
1967
+ export let cmp = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
1968
+ if (isSimpleNumber(x)) {
1969
+ if (isSimpleNumber(y)) {
1970
+ if (WasmI32.ltS(x, y)) -1n else if (WasmI32.gtS(x, y)) 1n else 0n
1791
1971
  } else {
1792
- let x = WasmI32.fromGrain(x)
1793
- let y = WasmI32.fromGrain(y)
1794
- numberEqual(x, y)
1972
+ let yBoxedNumberTag = boxedNumberTag(y)
1973
+ match (yBoxedNumberTag) {
1974
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1975
+ WasmI32.sub(0n, cmpSmallInt(y, x, false, totalOrdering))
1976
+ },
1977
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1978
+ WasmI32.sub(0n, cmpSmallInt(y, x, true, totalOrdering))
1979
+ },
1980
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1981
+ WasmI32.sub(0n, cmpBigInt(y, x))
1982
+ },
1983
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1984
+ WasmI32.sub(0n, cmpRational(y, x, totalOrdering))
1985
+ },
1986
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1987
+ WasmI32.sub(0n, cmpFloat(y, x, false, totalOrdering))
1988
+ },
1989
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1990
+ WasmI32.sub(0n, cmpFloat(y, x, true, totalOrdering))
1991
+ },
1992
+ _ => {
1993
+ throw UnknownNumberTag
1994
+ },
1995
+ }
1996
+ }
1997
+ } else {
1998
+ let xBoxedNumberTag = boxedNumberTag(x)
1999
+ match (xBoxedNumberTag) {
2000
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
2001
+ cmpSmallInt(x, y, false, totalOrdering)
2002
+ },
2003
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
2004
+ cmpSmallInt(x, y, true, totalOrdering)
2005
+ },
2006
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
2007
+ cmpBigInt(x, y)
2008
+ },
2009
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
2010
+ cmpRational(x, y, totalOrdering)
2011
+ },
2012
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
2013
+ cmpFloat(x, y, false, totalOrdering)
2014
+ },
2015
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
2016
+ cmpFloat(x, y, true, totalOrdering)
2017
+ },
2018
+ _ => {
2019
+ throw UnknownNumberTag
2020
+ },
1795
2021
  }
1796
2022
  }
1797
2023
  }
1798
2024
 
2025
+ @unsafe
2026
+ export let (<) = (x: Number, y: Number) => {
2027
+ let x = WasmI32.fromGrain(x)
2028
+ let y = WasmI32.fromGrain(y)
2029
+ WasmI32.ltS(cmp(x, y, false), 0n)
2030
+ }
2031
+
2032
+ @unsafe
2033
+ export let (>) = (x: Number, y: Number) => {
2034
+ let x = WasmI32.fromGrain(x)
2035
+ let y = WasmI32.fromGrain(y)
2036
+ WasmI32.gtS(cmp(x, y, false), 0n)
2037
+ }
2038
+
2039
+ @unsafe
2040
+ export let (<=) = (x: Number, y: Number) => {
2041
+ let x = WasmI32.fromGrain(x)
2042
+ let y = WasmI32.fromGrain(y)
2043
+ WasmI32.leS(cmp(x, y, false), 0n)
2044
+ }
2045
+
2046
+ @unsafe
2047
+ export let (>=) = (x: Number, y: Number) => {
2048
+ let x = WasmI32.fromGrain(x)
2049
+ let y = WasmI32.fromGrain(y)
2050
+ WasmI32.geS(cmp(x, y, false), 0n)
2051
+ }
2052
+
2053
+ @unsafe
2054
+ export let compare = (x: Number, y: Number) => {
2055
+ let x = WasmI32.fromGrain(x)
2056
+ let y = WasmI32.fromGrain(y)
2057
+ WasmI32.toGrain(tagSimple(cmp(x, y, true))): Number
2058
+ }
2059
+
1799
2060
  /*
1800
2061
  * ===== EQUAL =====
1801
2062
  */
@@ -1811,7 +2072,7 @@ export let numberEq = (x: Number, y: Number) => {
1811
2072
  * ===== LOGICAL OPERATIONS =====
1812
2073
  * Only valid for int-like numbers. Coerce to i64/bigInt and do operations
1813
2074
  */
1814
- // TODO: (#306) Semantics around when things should stay i32/i64
2075
+ // TODO(#306): Semantics around when things should stay i32/i64
1815
2076
 
1816
2077
  @unsafe
1817
2078
  export let lnot = (x: Number) => {
@@ -1833,7 +2094,15 @@ export let (<<) = (x: Number, y: Number) => {
1833
2094
  } else {
1834
2095
  let xval = coerceNumberToWasmI64(x)
1835
2096
  let yval = coerceNumberToWasmI64(y)
1836
- WasmI32.toGrain(reducedInteger(WasmI64.shl(xval, yval))): Number
2097
+ // if the number will be shifted beyond the end of the i64 range, promote to BigInt
2098
+ // (note that we subtract one leading zero, since the leading bit is the sign bit)
2099
+ if (WasmI64.leU(WasmI64.sub(WasmI64.clz(i64abs(xval)), 1N), yval)) {
2100
+ let xbi = coerceNumberToBigInt(x)
2101
+ let yval = coerceNumberToWasmI32(y)
2102
+ WasmI32.toGrain(reducedBigInteger(BI.shl(xbi, yval))): Number
2103
+ } else {
2104
+ WasmI32.toGrain(reducedInteger(WasmI64.shl(xval, yval))): Number
2105
+ }
1837
2106
  }
1838
2107
  }
1839
2108
 
@@ -2220,3 +2489,57 @@ export let isBigInt = x => {
2220
2489
  let x = WasmI32.fromGrain(x)
2221
2490
  isBigInt(x)
2222
2491
  }
2492
+
2493
+ // Scalbn is based on https://git.musl-libc.org/cgit/musl/tree/src/math/scalbn.c
2494
+ /*
2495
+ * ====================================================
2496
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
2497
+ *
2498
+ * Permission to use, copy, modify, and distribute this
2499
+ * software is freely granted, provided that this notice
2500
+ * is preserved.
2501
+ * ====================================================
2502
+ */
2503
+ /**
2504
+ * Multiplies a floating-point number by an integral power of 2.
2505
+ *
2506
+ * @param x: The floating-point value
2507
+ * @param n: The Integer exponent
2508
+ * @returns The result of x * 2^n
2509
+ *
2510
+ * @since v0.5.4
2511
+ */
2512
+ @unsafe
2513
+ export let scalbn = (x, n) => {
2514
+ let (>) = WasmI32.gtS
2515
+ let (<) = WasmI32.ltS
2516
+ let (*) = WasmF64.mul
2517
+ let (-) = WasmI32.sub
2518
+ let (+) = WasmI32.add
2519
+ let (<<) = WasmI64.shl
2520
+ // Constants
2521
+ let const_0x1p1023 = 8.98847e+307W
2522
+ let const_0x1p_1022 = 2.22507e-308W
2523
+ let const_0x1p53 = 9.0072e+15W
2524
+ let mut n = n
2525
+ let mut y = x
2526
+ if (n > 1023n) {
2527
+ y *= const_0x1p1023
2528
+ n -= 1023n
2529
+ if (n > 1023n) {
2530
+ y *= const_0x1p1023
2531
+ n -= 1023n
2532
+ if (n > 1023n) n = 1023n
2533
+ } else if (n < -1023n) {
2534
+ /* make sure final n < -53 to avoid double rounding in the subnormal range */
2535
+ y *= const_0x1p_1022 * const_0x1p53
2536
+ n += 1022n - 53n
2537
+ if (n < -1022n) {
2538
+ y *= const_0x1p_1022 * const_0x1p53
2539
+ n += 1022n - 53n
2540
+ if (n < -1022n) n = -1022n
2541
+ }
2542
+ }
2543
+ }
2544
+ y * WasmF64.reinterpretI64(WasmI64.extendI32S(0x3FFn + n) << 52N)
2545
+ }