18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is free software; you can redistribute it and/or
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  modify it under the terms of the GNU Lesser General Public
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License as published by the Free Software Foundation; either
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  version 2 of the License, or (at your option) any later version.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is distributed in the hope that it will be useful,
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  but WITHOUT ANY WARRANTY; without even the implied warranty of
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Lesser General Public License for more details.
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  You should have received a copy of the GNU Lesser General Public
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License along with this library; if not, write to the Free Software
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  USA
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "NumberPrototype.h"
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Error.h"
265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "JSFunction.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSString.h"
28d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "Operations.h"
295ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#include "dtoa.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/Assertions.h>
31e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include <wtf/DecimalNumber.h>
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/MathExtras.h>
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/Vector.h>
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace JSC {
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectASSERT_CLASS_FITS_IN_CELL(NumberPrototype);
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
39545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);
40545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*);
41545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*);
42545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*);
43545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*);
44545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ECMA 15.7.4
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben MurdochNumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, Structure* functionStructure)
492fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    : NumberObject(exec->globalData(), structure)
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    setInternalValue(exec->globalData(), jsNumber(0));
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The constructor will be added later, after NumberConstructor has been constructed
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum);
5681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum);
5781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum);
5881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum);
5981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum);
6081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toPrecision, numberProtoFuncToPrecision), DontEnum);
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ------------------------------ Functions ---------------------------
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ECMA 15.7.4.2 - 15.7.4.7
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
67e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blockstatic ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double &x)
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
69e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    JSValue v = thisValue.getJSNumber();
70e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (UNLIKELY(!v))
71e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return false;
72e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    x = v.uncheckedGetNumber();
73e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    return true;
74e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block}
75e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
76e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blockstatic ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined)
77e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{
78e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    result = 0;
79e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    isUndefined = false;
80e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
81e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    JSValue argument0 = exec->argument(0);
82e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (argument0.isUndefined()) {
83e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        isUndefined = true;
84e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return true;
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
87e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    double asDouble = argument0.toInteger(exec);
88e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (asDouble < low || asDouble > high)
89e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return false;
90e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
91e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    result = static_cast<int>(asDouble);
92e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    return true;
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
95e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// toExponential converts a number to a string, always formatting as an expoential.
96e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// This method takes an optional argument specifying a number of *decimal places*
97e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// to round the significand to (or, put another way, this method optionally rounds
98e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// to argument-plus-one significant figures).
99e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockEncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
101e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Get x (the double value of this, which should be a Number).
102e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    double x;
103e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!toThisNumber(exec->hostThisValue(), x))
104e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return throwVMTypeError(exec);
105e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
106e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Get the argument.
107e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    int decimalPlacesInExponent;
108e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    bool isUndefined;
109e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined))
110e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20"));
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
112e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Handle NaN and Infinity.
113e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (isnan(x) || isinf(x))
114e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return JSValue::encode(jsString(exec, UString::number(x)));
115e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
116e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Round if the argument is not undefined, always format as exponential.
117e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    NumberToStringBuffer buffer;
118e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    unsigned length = isUndefined
119a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        ? DecimalNumber(x).toStringExponential(buffer, WTF::NumberToStringBufferLength)
120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        : DecimalNumber(x, RoundingSignificantFigures, decimalPlacesInExponent + 1).toStringExponential(buffer, WTF::NumberToStringBufferLength);
121e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
122e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    return JSValue::encode(jsString(exec, UString(buffer, length)));
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
125e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// toFixed converts a number to a string, always formatting as an a decimal fraction.
126e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// This method takes an argument specifying a number of decimal places to round the
127e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// significand to. However when converting large values (1e+21 and above) this
128e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// method will instead fallback to calling ToString.
129e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockEncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
131e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Get x (the double value of this, which should be a Number).
132e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    JSValue thisValue = exec->hostThisValue();
133e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    JSValue v = thisValue.getJSNumber();
134e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!v)
135e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return throwVMTypeError(exec);
136e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    double x = v.uncheckedGetNumber();
137e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
138e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Get the argument.
139e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    int decimalPlaces;
140e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    bool isUndefined; // This is ignored; undefined treated as 0.
141e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
142e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20"));
143e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
144e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
145e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // This also covers Ininity, and structure the check so that NaN
146e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // values are also handled by numberToString
147e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!(fabs(x) < 1e+21))
148e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return JSValue::encode(jsString(exec, UString::number(x)));
149e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
150e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // The check above will return false for NaN or Infinity, these will be
151e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // handled by numberToString.
152e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    ASSERT(!isnan(x) && !isinf(x));
153e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
154e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Convert to decimal with rounding, and format as decimal.
155e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    NumberToStringBuffer buffer;
156a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    unsigned length = DecimalNumber(x, RoundingDecimalPlaces, decimalPlaces).toStringDecimal(buffer, WTF::NumberToStringBufferLength);
157e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    return JSValue::encode(jsString(exec, UString(buffer, length)));
158e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block}
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
160e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// toPrecision converts a number to a string, takeing an argument specifying a
161e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// number of significant figures to round the significand to. For positive
162e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// exponent, all values that can be represented using a decimal fraction will
163e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
164e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
165e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// For negative exponents values >= 1e-6 are formated as decimal fractions,
166e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// with smaller values converted to exponential representation.
167e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockEncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
168e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{
169e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Get x (the double value of this, which should be a Number).
170e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    JSValue thisValue = exec->hostThisValue();
171e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    JSValue v = thisValue.getJSNumber();
172e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!v)
173e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return throwVMTypeError(exec);
174e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    double x = v.uncheckedGetNumber();
175e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
176e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Get the argument.
177e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    int significantFigures;
178e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    bool isUndefined;
179e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
180e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21"));
181e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
182e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // To precision called with no argument is treated as ToString.
183e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (isUndefined)
184e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return JSValue::encode(jsString(exec, UString::number(x)));
185e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
186e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Handle NaN and Infinity.
187e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (isnan(x) || isinf(x))
188e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return JSValue::encode(jsString(exec, UString::number(x)));
189e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
190e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Convert to decimal with rounding.
191e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    DecimalNumber number(x, RoundingSignificantFigures, significantFigures);
192e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format
193e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // as decimal. Otherwise, format the number as an exponential.  Decimal format
194e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // demands a minimum of (exponent + 1) digits to represent a number, for example
195e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c)
196e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    NumberToStringBuffer buffer;
197e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    unsigned length = number.exponent() >= -6 && number.exponent() < significantFigures
198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        ? number.toStringDecimal(buffer, WTF::NumberToStringBufferLength)
199a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        : number.toStringExponential(buffer, WTF::NumberToStringBufferLength);
200e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    return JSValue::encode(jsString(exec, UString(buffer, length)));
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
203545e470e52f0ac6a3a072bf559c796b42c6066b6Ben MurdochEncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2055af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    JSValue thisValue = exec->hostThisValue();
2065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    JSValue v = thisValue.getJSNumber();
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!v)
208545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return throwVMTypeError(exec);
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2105af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    JSValue radixValue = exec->argument(0);
2116c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    int radix;
2126c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (radixValue.isInt32())
2136c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        radix = radixValue.asInt32();
2146c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    else if (radixValue.isUndefined())
2156c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        radix = 10;
2166c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    else
2176c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0
2186c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2196c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (radix == 10)
220545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return JSValue::encode(jsString(exec, v.toString(exec)));
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2226c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    static const char* const digits = "0123456789abcdefghijklmnopqrstuvwxyz";
2236c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2246c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // Fast path for number to character conversion.
2256c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (radix == 36) {
2266c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        if (v.isInt32()) {
2276c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            int x = v.asInt32();
2286c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            if (static_cast<unsigned>(x) < 36) { // Exclude negatives
2296c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen                JSGlobalData* globalData = &exec->globalData();
230545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch                return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, digits[x]));
2316c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            }
2326c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        }
2336c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    }
2346c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2356c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (radix < 2 || radix > 36)
236545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // INT_MAX results in 1024 characters left of the dot with radix 2
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // give the same space on the right side. safety checks are in place
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // unless someone finds a precise rule.
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char s[2048 + 3];
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* lastCharInString = s + sizeof(s) - 1;
243635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    double x = v.uncheckedGetNumber();
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isnan(x) || isinf(x))
245f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        return JSValue::encode(jsString(exec, UString::number(x)));
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool isNegative = x < 0.0;
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isNegative)
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        x = -x;
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    double integerPart = floor(x);
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* decimalPoint = s + sizeof(s) / 2;
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // convert integer portion
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* p = decimalPoint;
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    double d = integerPart;
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    do {
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int remainderDigit = static_cast<int>(fmod(d, radix));
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *--p = digits[remainderDigit];
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        d /= radix;
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } while ((d <= -1.0 || d >= 1.0) && s < p);
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isNegative)
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *--p = '-';
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* startOfResultString = p;
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(s <= startOfResultString);
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    d = x - integerPart;
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    p = decimalPoint;
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const double epsilon = 0.001; // TODO: guessed. base on radix ?
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool hasFractionalPart = (d < -epsilon || d > epsilon);
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (hasFractionalPart) {
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '.';
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        do {
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            d *= radix;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            const int digit = static_cast<int>(d);
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = digits[digit];
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            d -= digit;
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } while ((d < -epsilon || d > epsilon) && p < lastCharInString);
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *p = '\0';
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(p < s + sizeof(s));
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
284545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    return JSValue::encode(jsString(exec, startOfResultString));
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
287545e470e52f0ac6a3a072bf559c796b42c6066b6Ben MurdochEncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2895af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    JSValue thisValue = exec->hostThisValue();
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Not implemented yet.
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    JSValue v = thisValue.getJSNumber();
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!v)
294545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return throwVMTypeError(exec);
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
296545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    return JSValue::encode(jsString(exec, v.toString(exec)));
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
299545e470e52f0ac6a3a072bf559c796b42c6066b6Ben MurdochEncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3015af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke    JSValue thisValue = exec->hostThisValue();
3025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    JSValue v = thisValue.getJSNumber();
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!v)
304545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return throwVMTypeError(exec);
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
306545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    return JSValue::encode(v);
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace JSC
310