@@ -45458,6 +45458,262 @@ static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
4545845458 return JS_NewInt32(ctx, r);
4545945459}
4546045460
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+ typedef enum {
45465+ SUM_PRECISE_STATE_MINUS_ZERO,
45466+ SUM_PRECISE_STATE_FINITE,
45467+ SUM_PRECISE_STATE_INFINITY,
45468+ SUM_PRECISE_STATE_MINUS_INFINITY, /* must be after SUM_PRECISE_STATE_INFINITY */
45469+ SUM_PRECISE_STATE_NAN, /* must be after SUM_PRECISE_STATE_MINUS_INFINITY */
45470+ } SumPreciseStateEnum;
45471+
45472+ typedef struct {
45473+ uint64_t acc[SUM_PRECISE_ACC_LEN];
45474+ int n_limbs; /* acc is not necessarily normalized */
45475+ SumPreciseStateEnum state;
45476+ } SumPreciseState;
45477+
45478+ static void sum_precise_init(SumPreciseState *s)
45479+ {
45480+ s->state = SUM_PRECISE_STATE_MINUS_ZERO;
45481+ s->acc[0] = 0;
45482+ s->n_limbs = 1;
45483+ }
45484+
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)
45496+
45497+ static void sum_precise_add(SumPreciseState *s, double d)
45498+ {
45499+ uint64_t a, m, a0, carry, acc_sign, a_sign;
45500+ int sgn, e, p, n, i;
45501+ unsigned shift;
45502+
45503+ a = float64_as_uint64(d);
45504+ sgn = a >> 63;
45505+ e = (a >> 52) & ((1 << 11) - 1);
45506+ m = a & (((uint64_t)1 << 52) - 1);
45507+ if (unlikely(e == 2047)) {
45508+ if (m == 0) {
45509+ /* +/- infinity */
45510+ if (s->state == SUM_PRECISE_STATE_NAN ||
45511+ (s->state == SUM_PRECISE_STATE_MINUS_INFINITY && !sgn) ||
45512+ (s->state == SUM_PRECISE_STATE_INFINITY && sgn)) {
45513+ s->state = SUM_PRECISE_STATE_NAN;
45514+ } else {
45515+ s->state = SUM_PRECISE_STATE_INFINITY + sgn;
45516+ }
45517+ } else {
45518+ /* NaN */
45519+ s->state = SUM_PRECISE_STATE_NAN;
45520+ }
45521+ } else if (e == 0) {
45522+ if (likely(m == 0)) {
45523+ /* zero */
45524+ if (s->state == SUM_PRECISE_STATE_MINUS_ZERO && !sgn)
45525+ s->state = SUM_PRECISE_STATE_FINITE;
45526+ } else {
45527+ /* subnormal */
45528+ p = 0;
45529+ shift = 0;
45530+ goto add;
45531+ }
45532+ } else {
45533+ m |= (uint64_t)1 << 52;
45534+ shift = e - 1;
45535+ p = shift / 64;
45536+ /* 'p' is the position of a0 in acc */
45537+ shift %= 64;
45538+ 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;
45564+ } 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+ }
45573+ }
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;
45580+ }
45581+ done:
45582+ s->n_limbs = n;
45583+ }
45584+ }
45585+
45586+ static double sum_precise_get_result(SumPreciseState *s)
45587+ {
45588+ int n, shift, e, p, is_neg, i;
45589+ uint64_t m, addend, carry;
45590+
45591+ if (s->state != SUM_PRECISE_STATE_FINITE) {
45592+ switch(s->state) {
45593+ default:
45594+ case SUM_PRECISE_STATE_MINUS_ZERO:
45595+ return -0.0;
45596+ case SUM_PRECISE_STATE_INFINITY:
45597+ return INFINITY;
45598+ case SUM_PRECISE_STATE_MINUS_INFINITY:
45599+ return -INFINITY;
45600+ case SUM_PRECISE_STATE_NAN:
45601+ return NAN;
45602+ }
45603+ }
45604+
45605+ /* 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+ #if 0
45619+ {
45620+ printf("res=");
45621+ for(i = n - 1; i >= 0; i--)
45622+ printf(" %016lx", s->acc[i]);
45623+ printf("\n");
45624+ }
45625+ #endif
45626+ /* zero result. The spec tells it is always positive in the finite case */
45627+ if (n == 0)
45628+ return 0.0;
45629+ /* subnormal case */
45630+ if (n == 1 && s->acc[0] < ((uint64_t)1 << 52))
45631+ return uint64_as_float64(((uint64_t)is_neg << 63) | s->acc[0]);
45632+ /* normal case */
45633+ e = n * 64;
45634+ p = n - 1;
45635+ m = s->acc[p];
45636+ shift = clz64(m);
45637+ e = e - shift - 52;
45638+ if (shift != 0) {
45639+ m <<= shift;
45640+ if (p > 0) {
45641+ int shift1;
45642+ uint64_t nz;
45643+ p--;
45644+ shift1 = 64 - shift;
45645+ nz = s->acc[p] & (((uint64_t)1 << shift1) - 1);
45646+ m = m | (s->acc[p] >> shift1) | (nz != 0);
45647+ }
45648+ }
45649+ if ((m & ((1 << 10) - 1)) == 0) {
45650+ /* see if the LSB part is non zero for the final rounding */
45651+ while (p > 0) {
45652+ p--;
45653+ if (s->acc[p] != 0) {
45654+ m |= 1;
45655+ break;
45656+ }
45657+ }
45658+ }
45659+ /* rounding to nearest with ties to even */
45660+ addend = (1 << 10) - 1 + ((m >> 11) & 1);
45661+ m = (m + addend) >> 11;
45662+ /* handle overflow in the rounding */
45663+ if (m == 0)
45664+ e++;
45665+ if (unlikely(e >= 2047)) {
45666+ /* infinity */
45667+ return uint64_as_float64(((uint64_t)is_neg << 63) | ((uint64_t)2047 << 52));
45668+ } else {
45669+ m &= (((uint64_t)1 << 52) - 1);
45670+ return uint64_as_float64(((uint64_t)is_neg << 63) | ((uint64_t)e << 52) | m);
45671+ }
45672+ }
45673+
45674+ static JSValue js_math_sumPrecise(JSContext *ctx, JSValueConst this_val,
45675+ int argc, JSValueConst *argv)
45676+ {
45677+ JSValue iter, next, item, ret;
45678+ uint32_t tag;
45679+ int done;
45680+ double d;
45681+ SumPreciseState s_s, *s = &s_s;
45682+
45683+ iter = JS_GetIterator(ctx, argv[0], FALSE);
45684+ if (JS_IsException(iter))
45685+ return JS_EXCEPTION;
45686+ ret = JS_EXCEPTION;
45687+ next = JS_GetProperty(ctx, iter, JS_ATOM_next);
45688+ if (JS_IsException(next))
45689+ goto fail;
45690+ sum_precise_init(s);
45691+ for (;;) {
45692+ item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
45693+ if (JS_IsException(item))
45694+ goto fail;
45695+ if (done)
45696+ break;
45697+ tag = JS_VALUE_GET_TAG(item);
45698+ if (JS_TAG_IS_FLOAT64(tag)) {
45699+ d = JS_VALUE_GET_FLOAT64(item);
45700+ } else if (tag == JS_TAG_INT) {
45701+ d = JS_VALUE_GET_INT(item);
45702+ } else {
45703+ JS_FreeValue(ctx, item);
45704+ JS_ThrowTypeError(ctx, "not a number");
45705+ JS_IteratorClose(ctx, iter, TRUE);
45706+ goto fail;
45707+ }
45708+ sum_precise_add(s, d);
45709+ }
45710+ ret = __JS_NewFloat64(ctx, sum_precise_get_result(s));
45711+ fail:
45712+ JS_FreeValue(ctx, iter);
45713+ JS_FreeValue(ctx, next);
45714+ return ret;
45715+ }
45716+
4546145717/* xorshift* random number generator by Marsaglia */
4546245718static uint64_t xorshift64star(uint64_t *pstate)
4546345719{
@@ -45531,6 +45787,7 @@ static const JSCFunctionListEntry js_math_funcs[] = {
4553145787 JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
4553245788 JS_CFUNC_DEF("imul", 2, js_math_imul ),
4553345789 JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
45790+ JS_CFUNC_DEF("sumPrecise", 1, js_math_sumPrecise ),
4553445791 JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
4553545792 JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
4553645793 JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
0 commit comments