diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c index 417e9ceade3..e1ff50c055d 100644 --- a/dlls/jscript/number.c +++ b/dlls/jscript/number.c @@ -150,6 +150,70 @@ static inline void number_to_fixed(double val, int prec, BSTR *out) *out = str; } +static inline void number_to_exponential(double val, int prec, BSTR *out) +{ + WCHAR buf[NUMBER_DTOA_SIZE], *pbuf; + int dec_point, size, buf_size, exp_size = 1; + BOOL neg = FALSE; + BSTR str; + + if(val < 0) { + neg = TRUE; + val = -val; + } + + buf_size = prec+2; + if(buf_size<2 || buf_size>NUMBER_DTOA_SIZE) + buf_size = NUMBER_DTOA_SIZE; + dtoa(val, buf, buf_size, &dec_point); + buf_size--; + if(prec == -1) + for(; buf_size>1 && buf[buf_size-1]=='0'; buf_size--) + buf[buf_size-1] = 0; + + size = 10; + while(dec_point>=size || dec_point<=-size) { + size *= 10; + exp_size++; + } + + if(buf_size == 1) + size = buf_size+2+exp_size; /* 2 = strlen(e+) */ + else if(prec == -1) + size = buf_size+3+exp_size; /* 3 = strlen(.e+) */ + else + size = prec+4+exp_size; /* 4 = strlen(0.e+) */ + if(neg) + size++; + str = SysAllocStringLen(NULL, size); + + size = 0; + pbuf = buf; + if(neg) + str[size++] = '-'; + str[size++] = *pbuf++; + if(buf_size != 1) { + str[size++] = '.'; + while(*pbuf) + str[size++] = *pbuf++; + for(; prec>buf_size-1; prec--) + str[size++] = '0'; + } + str[size++] = 'e'; + if(dec_point >= 0) { + str[size++] = '+'; + }else { + str[size++] = '-'; + dec_point = -dec_point; + } + for(str[size]='0', size+=exp_size-1; dec_point>0; dec_point/=10) + str[size--] = '0'+dec_point%10; + size += exp_size+1; + str[size] = 0; + + *out = str; +} + /* ECMA-262 3rd Edition 15.7.4.2 */ static HRESULT Number_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) @@ -330,8 +394,47 @@ static HRESULT Number_toFixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI static HRESULT Number_toExponential(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) { - FIXME("\n"); - return E_NOTIMPL; + NumberInstance *number; + DOUBLE val; + INT prec = 0; + BSTR str; + HRESULT hres; + + TRACE("\n"); + + if(!(number = number_this(jsthis))) + return throw_type_error(ctx, ei, JS_E_NUMBER_EXPECTED, NULL); + + if(arg_cnt(dp)) { + hres = to_int32(ctx, get_arg(dp, 0), ei, &prec); + if(FAILED(hres)) + return hres; + + if(prec<0 || prec>20) + return throw_range_error(ctx, ei, JS_E_FRACTION_DIGITS_OUT_OF_RANGE, NULL); + } + + val = number->value; + if(isinf(val) || isnan(val)) { + VARIANT v; + + num_set_val(&v, val); + hres = to_string(ctx, &v, ei, &str); + if(FAILED(hres)) + return hres; + }else { + if(!prec) + prec--; + number_to_exponential(val, prec, &str); + } + + if(retv) { + V_VT(retv) = VT_BSTR; + V_BSTR(retv) = str; + }else { + SysFreeString(str); + } + return S_OK; } static HRESULT Number_toPrecision(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 70b28efb418..a0e23fb9845 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -1046,6 +1046,21 @@ ok(tmp === "Infinity", "num(1000000000000000128) = " + tmp); tmp = (new Number(0.12345678901234567890123)).toFixed(20); ok(tmp === "0.12345678901234568000", "num(0.12345678901234567890123) = " + tmp); +tmp = (new Number(2)).toExponential(3); +ok(tmp === "2.000e+0", "num(2).toExponential(3) = " + tmp); +tmp = (new Number(1.17e-32)).toExponential(20); +ok(tmp === "1.17000000000000000000e-32", "num(1.17e-32).toExponential(20) = " + tmp); +tmp = (new Number(0)).toExponential(7); +ok(tmp === "0.0000000e+0", "num(0).toExponential(7) = " + tmp); +tmp = (new Number(0)).toExponential(0); +ok(tmp === "0e+0", "num(0).toExponential() = " + tmp); +tmp = (new Number(-13.7567)).toExponential(); +ok(tmp === "-1.37567e+1", "num(-13.7567).toExponential() = " + tmp); +tmp = (new Number(-32.1)).toExponential(); +ok(tmp === "-3.21e+1", "num(-32.1).toExponential() = " + tmp); +tmp = (new Number(4723.4235)).toExponential(); +ok(tmp === "4.7234235e+3", "num(4723.4235).toExponential() = " + tmp); + ok(Number() === 0, "Number() = " + Number()); ok(Number(false) === 0, "Number(false) = " + Number(false)); ok(Number("43") === 43, "Number('43') = " + Number("43"));