@@ -45458,47 +45458,59 @@ static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
45458
45458
return JS_NewInt32(ctx, r);
45459
45459
}
45460
45460
45461
- /* we add one extra limb to avoid having to test for overflows during the sum */
45462
- #define SUM_PRECISE_ACC_LEN 34
45463
-
45464
45461
typedef enum {
45465
- SUM_PRECISE_STATE_MINUS_ZERO,
45466
45462
SUM_PRECISE_STATE_FINITE,
45467
45463
SUM_PRECISE_STATE_INFINITY,
45468
45464
SUM_PRECISE_STATE_MINUS_INFINITY, /* must be after SUM_PRECISE_STATE_INFINITY */
45469
45465
SUM_PRECISE_STATE_NAN, /* must be after SUM_PRECISE_STATE_MINUS_INFINITY */
45470
45466
} SumPreciseStateEnum;
45471
45467
45468
+ #define SP_LIMB_BITS 56
45469
+ #define SP_RND_BITS (SP_LIMB_BITS - 53)
45470
+ /* we add one extra limb to avoid having to test for overflows during the sum */
45471
+ #define SUM_PRECISE_ACC_LEN 39
45472
+
45473
+ #define SUM_PRECISE_COUNTER_INIT 250
45474
+
45472
45475
typedef struct {
45473
- uint64_t acc[SUM_PRECISE_ACC_LEN];
45474
- int n_limbs; /* acc is not necessarily normalized */
45475
45476
SumPreciseStateEnum state;
45477
+ uint32_t counter;
45478
+ int n_limbs; /* 'acc' contains n_limbs and is not necessarily
45479
+ acc[n_limb - 1] may be 0. 0 indicates minus zero
45480
+ result when state = SUM_PRECISE_STATE_FINITE */
45481
+ int64_t acc[SUM_PRECISE_ACC_LEN];
45476
45482
} SumPreciseState;
45477
45483
45478
45484
static void sum_precise_init(SumPreciseState *s)
45479
45485
{
45480
- s->state = SUM_PRECISE_STATE_MINUS_ZERO;
45481
- s->acc[0] = 0;
45482
- s->n_limbs = 1;
45486
+ memset(s->acc, 0, sizeof(s->acc));
45487
+ s->state = SUM_PRECISE_STATE_FINITE;
45488
+ s->counter = SUM_PRECISE_COUNTER_INIT;
45489
+ s->n_limbs = 0;
45483
45490
}
45484
45491
45485
- #define ADDC64(res, carry_out, op1, op2, carry_in) \
45486
- do { \
45487
- uint64_t __v, __a, __k, __k1; \
45488
- __v = (op1); \
45489
- __a = __v + (op2); \
45490
- __k1 = __a < __v; \
45491
- __k = (carry_in); \
45492
- __a = __a + __k; \
45493
- carry_out = (__a < __k) | __k1; \
45494
- res = __a; \
45495
- } while (0)
45492
+ static void sum_precise_renorm(SumPreciseState *s)
45493
+ {
45494
+ int64_t v, carry;
45495
+ int i;
45496
+
45497
+ carry = 0;
45498
+ for(i = 0; i < s->n_limbs; i++) {
45499
+ v = s->acc[i] + carry;
45500
+ s->acc[i] = v & (((uint64_t)1 << SP_LIMB_BITS) - 1);
45501
+ carry = v >> SP_LIMB_BITS;
45502
+ }
45503
+ /* we add a failsafe but it should be never reached in a
45504
+ reasonnable amount of time */
45505
+ if (carry != 0 && s->n_limbs < SUM_PRECISE_ACC_LEN)
45506
+ s->acc[s->n_limbs++] = carry;
45507
+ }
45496
45508
45497
45509
static void sum_precise_add(SumPreciseState *s, double d)
45498
45510
{
45499
- uint64_t a, m, a0, carry, acc_sign, a_sign ;
45500
- int sgn, e, p, n, i ;
45501
- unsigned shift;
45511
+ uint64_t a, m, a0, a1 ;
45512
+ int sgn, e, p;
45513
+ unsigned int shift;
45502
45514
45503
45515
a = float64_as_uint64(d);
45504
45516
sgn = a >> 63;
@@ -45521,78 +45533,50 @@ static void sum_precise_add(SumPreciseState *s, double d)
45521
45533
} else if (e == 0) {
45522
45534
if (likely(m == 0)) {
45523
45535
/* zero */
45524
- if (s->state == SUM_PRECISE_STATE_MINUS_ZERO && !sgn)
45525
- s->state = SUM_PRECISE_STATE_FINITE ;
45536
+ if (s->n_limbs == 0 && !sgn)
45537
+ s->n_limbs = 1 ;
45526
45538
} else {
45527
45539
/* subnormal */
45528
45540
p = 0;
45529
45541
shift = 0;
45530
45542
goto add;
45531
45543
}
45532
45544
} else {
45545
+ /* Note: we sum even if state != SUM_PRECISE_STATE_FINITE to
45546
+ avoid tests */
45533
45547
m |= (uint64_t)1 << 52;
45534
45548
shift = e - 1;
45535
- p = shift / 64;
45536
- /* 'p' is the position of a0 in acc */
45537
- shift %= 64;
45549
+ /* 'p' is the position of a0 in acc. The division is normally
45550
+ implementation as a multiplication by the compiler. */
45551
+ p = shift / SP_LIMB_BITS;
45552
+ shift %= SP_LIMB_BITS;
45538
45553
add:
45539
- if (s->state >= SUM_PRECISE_STATE_INFINITY)
45540
- return;
45541
- s->state = SUM_PRECISE_STATE_FINITE;
45542
- n = s->n_limbs;
45543
-
45544
- acc_sign = (int64_t)s->acc[n - 1] >> 63;
45545
-
45546
- /* sign extend acc */
45547
- for(i = n; i <= p; i++)
45548
- s->acc[i] = acc_sign;
45549
-
45550
- carry = sgn;
45551
- a_sign = -sgn;
45552
- a0 = m << shift;
45553
- ADDC64(s->acc[p], carry, s->acc[p], a0 ^ a_sign, carry);
45554
- if (shift >= 12) {
45555
- p++;
45556
- if (p >= n)
45557
- s->acc[p] = acc_sign;
45558
- a0 = m >> (64 - shift);
45559
- ADDC64(s->acc[p], carry, s->acc[p], a0 ^ a_sign, carry);
45560
- }
45561
- p++;
45562
- if (p >= n) {
45563
- n = p;
45554
+ a0 = (m << shift) & (((uint64_t)1 << SP_LIMB_BITS) - 1);
45555
+ a1 = m >> (SP_LIMB_BITS - shift);
45556
+ if (!sgn) {
45557
+ s->acc[p] += a0;
45558
+ s->acc[p + 1] += a1;
45564
45559
} else {
45565
- /* carry */
45566
- for(i = p; i < n; i++) {
45567
- /* if 'a' positive: stop condition: carry = 0.
45568
- if 'a' negative: stop condition: carry = 1. */
45569
- if (carry == sgn)
45570
- goto done;
45571
- ADDC64(s->acc[i], carry, s->acc[i], a_sign, carry);
45572
- }
45560
+ s->acc[p] -= a0;
45561
+ s->acc[p + 1] -= a1;
45573
45562
}
45574
-
45575
- /* extend the accumulator if needed */
45576
- a0 = carry + acc_sign + a_sign;
45577
- /* -1 <= a0 <= 1 (if both acc and a are negative, carry is set) */
45578
- if (a0 != ((int64_t)s->acc[n - 1] >> 63)) {
45579
- s->acc[n++] = a0;
45563
+ s->n_limbs = max_int(s->n_limbs, p + 2);
45564
+
45565
+ if (unlikely(--s->counter == 0)) {
45566
+ s->counter = SUM_PRECISE_COUNTER_INIT;
45567
+ sum_precise_renorm(s);
45580
45568
}
45581
- done:
45582
- s->n_limbs = n;
45583
45569
}
45584
45570
}
45585
45571
45586
45572
static double sum_precise_get_result(SumPreciseState *s)
45587
45573
{
45588
- int n, shift, e, p, is_neg, i ;
45589
- uint64_t m, addend, carry ;
45574
+ int n, shift, e, p, is_neg;
45575
+ uint64_t m, addend;
45590
45576
45591
45577
if (s->state != SUM_PRECISE_STATE_FINITE) {
45592
45578
switch(s->state) {
45593
45579
default:
45594
- case SUM_PRECISE_STATE_MINUS_ZERO:
45595
- return -0.0;
45596
45580
case SUM_PRECISE_STATE_INFINITY:
45597
45581
return INFINITY;
45598
45582
case SUM_PRECISE_STATE_MINUS_INFINITY:
@@ -45602,51 +45586,66 @@ static double sum_precise_get_result(SumPreciseState *s)
45602
45586
}
45603
45587
}
45604
45588
45589
+ sum_precise_renorm(s);
45590
+
45605
45591
/* extract the sign and absolute value */
45606
- n = s->n_limbs;
45607
- is_neg = s->acc[n - 1] >> 63;
45608
- if (is_neg) {
45609
- /* acc = -acc */
45610
- carry = 1;
45611
- for(i = 0; i < n; i++) {
45612
- ADDC64(s->acc[i], carry, ~s->acc[i], 0, carry);
45613
- }
45614
- }
45615
- /* normalize */
45616
- while (n > 0 && s->acc[n - 1] == 0)
45617
- n--;
45618
45592
#if 0
45619
45593
{
45620
- printf("res=");
45621
- for(i = n - 1; i >= 0; i--)
45622
- printf(" %016lx", s->acc[i]);
45594
+ int i;
45595
+ printf("len=%d:", s->n_limbs);
45596
+ for(i = s->n_limbs - 1; i >= 0; i--)
45597
+ printf(" %014lx", s->acc[i]);
45623
45598
printf("\n");
45624
45599
}
45625
45600
#endif
45601
+ n = s->n_limbs;
45602
+ /* minus zero result */
45603
+ if (n == 0)
45604
+ return -0.0;
45605
+
45606
+ /* normalize */
45607
+ while (n > 0 && s->acc[n - 1] == 0)
45608
+ n--;
45626
45609
/* zero result. The spec tells it is always positive in the finite case */
45627
45610
if (n == 0)
45628
45611
return 0.0;
45612
+ is_neg = (s->acc[n - 1] < 0);
45613
+ if (is_neg) {
45614
+ uint64_t v, carry;
45615
+ int i;
45616
+ /* negate */
45617
+ /* XXX: do it only when needed */
45618
+ carry = 1;
45619
+ for(i = 0; i < n - 1; i++) {
45620
+ v = (((uint64_t)1 << SP_LIMB_BITS) - 1) - s->acc[i] + carry;
45621
+ carry = v >> SP_LIMB_BITS;
45622
+ s->acc[i] = v & (((uint64_t)1 << SP_LIMB_BITS) - 1);
45623
+ }
45624
+ s->acc[n - 1] = -s->acc[n - 1] + carry - 1;
45625
+ while (n > 1 && s->acc[n - 1] == 0)
45626
+ n--;
45627
+ }
45629
45628
/* subnormal case */
45630
45629
if (n == 1 && s->acc[0] < ((uint64_t)1 << 52))
45631
45630
return uint64_as_float64(((uint64_t)is_neg << 63) | s->acc[0]);
45632
45631
/* normal case */
45633
- e = n * 64 ;
45632
+ e = n * SP_LIMB_BITS ;
45634
45633
p = n - 1;
45635
45634
m = s->acc[p];
45636
- shift = clz64(m);
45635
+ shift = clz64(m) - (64 - SP_LIMB_BITS) ;
45637
45636
e = e - shift - 52;
45638
45637
if (shift != 0) {
45639
45638
m <<= shift;
45640
45639
if (p > 0) {
45641
45640
int shift1;
45642
45641
uint64_t nz;
45643
45642
p--;
45644
- shift1 = 64 - shift;
45643
+ shift1 = SP_LIMB_BITS - shift;
45645
45644
nz = s->acc[p] & (((uint64_t)1 << shift1) - 1);
45646
45645
m = m | (s->acc[p] >> shift1) | (nz != 0);
45647
45646
}
45648
45647
}
45649
- if ((m & ((1 << 10 ) - 1)) == 0 ) {
45648
+ if ((m & ((1 << SP_RND_BITS ) - 1)) == (1 << (SP_RND_BITS - 1)) ) {
45650
45649
/* see if the LSB part is non zero for the final rounding */
45651
45650
while (p > 0) {
45652
45651
p--;
@@ -45657,10 +45656,10 @@ static double sum_precise_get_result(SumPreciseState *s)
45657
45656
}
45658
45657
}
45659
45658
/* rounding to nearest with ties to even */
45660
- addend = (1 << 10) - 1 + ((m >> 11 ) & 1);
45661
- m = (m + addend) >> 11 ;
45659
+ addend = (1 << (SP_RND_BITS - 1)) - 1 + ((m >> SP_RND_BITS ) & 1);
45660
+ m = (m + addend) >> SP_RND_BITS ;
45662
45661
/* handle overflow in the rounding */
45663
- if (m == 0 )
45662
+ if (m == ((uint64_t)1 << 53) )
45664
45663
e++;
45665
45664
if (unlikely(e >= 2047)) {
45666
45665
/* infinity */
0 commit comments