mirror of
				https://github.com/bellard/quickjs.git
				synced 2025-05-29 01:49:18 +08:00 
			
		
		
		
	Improve Number.prototype.toString for radix other than 10
- fix the conversions for integers and exact fractions - approximate approach for other cases. - bypass floating point conversions for JS_TAG_INT values - avoid divisions for base 10 integer conversions
This commit is contained in:
		
							parent
							
								
									a78d2cbf7c
								
							
						
					
					
						commit
						8d64731eb8
					
				
							
								
								
									
										107
									
								
								quickjs.c
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								quickjs.c
									
									
									
									
									
								
							@ -11328,6 +11328,8 @@ static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
 | 
				
			|||||||
#endif /* CONFIG_BIGNUM */
 | 
					#endif /* CONFIG_BIGNUM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 2 <= base <= 36 */
 | 
					/* 2 <= base <= 36 */
 | 
				
			||||||
 | 
					static char const digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *i64toa(char *buf_end, int64_t n, unsigned int base)
 | 
					static char *i64toa(char *buf_end, int64_t n, unsigned int base)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *q = buf_end;
 | 
					    char *q = buf_end;
 | 
				
			||||||
@ -11339,15 +11341,20 @@ static char *i64toa(char *buf_end, int64_t n, unsigned int base)
 | 
				
			|||||||
        n = -n;
 | 
					        n = -n;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    *--q = '\0';
 | 
					    *--q = '\0';
 | 
				
			||||||
    do {
 | 
					    if (base == 10) {
 | 
				
			||||||
        digit = (uint64_t)n % base;
 | 
					        /* division by known base uses multiplication */
 | 
				
			||||||
        n = (uint64_t)n / base;
 | 
					        do {
 | 
				
			||||||
        if (digit < 10)
 | 
					            digit = (uint64_t)n % 10;
 | 
				
			||||||
            digit += '0';
 | 
					            n = (uint64_t)n / 10;
 | 
				
			||||||
        else
 | 
					            *--q = '0' + digit;
 | 
				
			||||||
            digit += 'a' - 10;
 | 
					        } while (n != 0);
 | 
				
			||||||
        *--q = digit;
 | 
					    } else {
 | 
				
			||||||
    } while (n != 0);
 | 
					        do {
 | 
				
			||||||
 | 
					            digit = (uint64_t)n % base;
 | 
				
			||||||
 | 
					            n = (uint64_t)n / base;
 | 
				
			||||||
 | 
					            *--q = digits[digit];
 | 
				
			||||||
 | 
					        } while (n != 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (is_neg)
 | 
					    if (is_neg)
 | 
				
			||||||
        *--q = '-';
 | 
					        *--q = '-';
 | 
				
			||||||
    return q;
 | 
					    return q;
 | 
				
			||||||
@ -11595,6 +11602,80 @@ static JSValue js_dtoa(JSContext *ctx,
 | 
				
			|||||||
    return JS_NewString(ctx, buf);
 | 
					    return JS_NewString(ctx, buf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static JSValue js_dtoa_radix(JSContext *ctx, double d, int radix)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char buf[2200], *ptr, *ptr2;
 | 
				
			||||||
 | 
					    /* d is finite */
 | 
				
			||||||
 | 
					    int sign = d < 0;
 | 
				
			||||||
 | 
					    int digit;
 | 
				
			||||||
 | 
					    double frac, d0;
 | 
				
			||||||
 | 
					    int64_t n0 = 0;
 | 
				
			||||||
 | 
					    d = fabs(d);
 | 
				
			||||||
 | 
					    d0 = trunc(d);
 | 
				
			||||||
 | 
					    frac = d - d0;
 | 
				
			||||||
 | 
					    ptr = buf + 1100;
 | 
				
			||||||
 | 
					    *ptr = '\0';
 | 
				
			||||||
 | 
					    if (d0 <= MAX_SAFE_INTEGER) {
 | 
				
			||||||
 | 
					        int64_t n = n0 = (int64_t)d0;
 | 
				
			||||||
 | 
					        while (n >= radix) {
 | 
				
			||||||
 | 
					            digit = n % radix;
 | 
				
			||||||
 | 
					            n = n / radix;
 | 
				
			||||||
 | 
					            *--ptr = digits[digit];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        *--ptr = digits[(int)n];
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        /* no decimals */
 | 
				
			||||||
 | 
					        while (d0 >= radix) {
 | 
				
			||||||
 | 
					            digit = fmod(d0, radix);
 | 
				
			||||||
 | 
					            d0 = trunc(d0 / radix);
 | 
				
			||||||
 | 
					            if (d0 >= MAX_SAFE_INTEGER)
 | 
				
			||||||
 | 
					                digit = 0;
 | 
				
			||||||
 | 
					            *--ptr = digits[digit];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        *--ptr = digits[(int)d0];
 | 
				
			||||||
 | 
					        goto done;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (frac != 0) {
 | 
				
			||||||
 | 
					        double log2_radix = log2(radix);
 | 
				
			||||||
 | 
					        double prec = 1023 + 51;  // handle subnormals
 | 
				
			||||||
 | 
					        ptr2 = buf + 1100;
 | 
				
			||||||
 | 
					        *ptr2++ = '.';
 | 
				
			||||||
 | 
					        while (frac != 0 && n0 <= MAX_SAFE_INTEGER/2 && prec > 0) {
 | 
				
			||||||
 | 
					            frac *= radix;
 | 
				
			||||||
 | 
					            digit = trunc(frac);
 | 
				
			||||||
 | 
					            frac -= digit;
 | 
				
			||||||
 | 
					            *ptr2++ = digits[digit];
 | 
				
			||||||
 | 
					            n0 = n0 * radix + digit;
 | 
				
			||||||
 | 
					            prec -= log2_radix;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        *ptr2 = '\0';
 | 
				
			||||||
 | 
					        if (frac * radix >= radix / 2) {
 | 
				
			||||||
 | 
					            char nine = digits[radix - 1];
 | 
				
			||||||
 | 
					            // round to closest
 | 
				
			||||||
 | 
					            while (ptr2[-1] == nine)
 | 
				
			||||||
 | 
					                *--ptr2 = '\0';
 | 
				
			||||||
 | 
					            if (ptr2[-1] == '.') {
 | 
				
			||||||
 | 
					                *--ptr2 = '\0';
 | 
				
			||||||
 | 
					                while (ptr2[-1] == nine)
 | 
				
			||||||
 | 
					                    *--ptr2 = '0';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (ptr2 - 1 == ptr)
 | 
				
			||||||
 | 
					                *--ptr = '1';
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                ptr2[-1] += 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            while (ptr2[-1] == '0')
 | 
				
			||||||
 | 
					                *--ptr2 = '\0';
 | 
				
			||||||
 | 
					            if (ptr2[-1] == '.')
 | 
				
			||||||
 | 
					                *--ptr2 = '\0';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
					    ptr[-1] = '-';
 | 
				
			||||||
 | 
					    ptr -= sign;
 | 
				
			||||||
 | 
					    return JS_NewString(ctx, ptr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
 | 
					JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint32_t tag;
 | 
					    uint32_t tag;
 | 
				
			||||||
@ -40975,8 +41056,16 @@ static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
 | 
				
			|||||||
        if (base < 0)
 | 
					        if (base < 0)
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
 | 
				
			||||||
 | 
					        char buf1[70], *ptr;
 | 
				
			||||||
 | 
					        ptr = i64toa(buf1 + sizeof(buf1), JS_VALUE_GET_INT(val), base);
 | 
				
			||||||
 | 
					        return JS_NewString(ctx, ptr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (JS_ToFloat64Free(ctx, &d, val))
 | 
					    if (JS_ToFloat64Free(ctx, &d, val))
 | 
				
			||||||
        return JS_EXCEPTION;
 | 
					        return JS_EXCEPTION;
 | 
				
			||||||
 | 
					    if (base != 10 && isfinite(d)) {
 | 
				
			||||||
 | 
					        return js_dtoa_radix(ctx, d, base);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
 | 
					    return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
 | 
				
			||||||
 fail:
 | 
					 fail:
 | 
				
			||||||
    JS_FreeValue(ctx, val);
 | 
					    JS_FreeValue(ctx, val);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user