2 * Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
3 * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
23 #include "NumberPrototype.h"
25 #include "BigInteger.h"
27 #include "JSFunction.h"
28 #include "JSGlobalObject.h"
30 #include "Operations.h"
31 #include "Uint16WithFraction.h"
33 #include <wtf/Assertions.h>
34 #include <wtf/MathExtras.h>
35 #include <wtf/Vector.h>
36 #include <wtf/dtoa/double-conversion.h>
38 using namespace WTF::double_conversion;
40 // To avoid conflict with WTF::StringBuilder.
41 typedef WTF::double_conversion::StringBuilder DoubleConversionStringBuilder;
45 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);
46 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*);
47 static EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*);
48 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*);
49 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*);
50 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
54 #include "NumberPrototype.lut.h"
58 const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) };
60 /* Source for NumberPrototype.lut.h
61 @begin numberPrototypeTable
62 toString numberProtoFuncToString DontEnum|Function 1
63 toLocaleString numberProtoFuncToLocaleString DontEnum|Function 0
64 valueOf numberProtoFuncValueOf DontEnum|Function 0
65 toFixed numberProtoFuncToFixed DontEnum|Function 1
66 toExponential numberProtoFuncToExponential DontEnum|Function 1
67 toPrecision numberProtoFuncToPrecision DontEnum|Function 1
71 ASSERT_CLASS_FITS_IN_CELL(NumberPrototype);
73 NumberPrototype::NumberPrototype(ExecState* exec, Structure* structure)
74 : NumberObject(exec->globalData(), structure)
78 void NumberPrototype::finishCreation(ExecState* exec, JSGlobalObject*)
80 Base::finishCreation(exec->globalData());
81 setInternalValue(exec->globalData(), jsNumber(0));
83 ASSERT(inherits(&s_info));
86 bool NumberPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
88 return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec), jsCast<NumberPrototype*>(cell), propertyName, slot);
91 bool NumberPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
93 return getStaticFunctionDescriptor<NumberObject>(exec, ExecState::numberPrototypeTable(exec), jsCast<NumberPrototype*>(object), propertyName, descriptor);
96 // ------------------------------ Functions ---------------------------
98 static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double& x)
100 if (thisValue.isInt32()) {
101 x = thisValue.asInt32();
105 if (thisValue.isDouble()) {
106 x = thisValue.asDouble();
110 if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isNumberObject()) {
111 x = static_cast<const NumberObject*>(thisValue.asCell())->internalValue().asNumber();
118 static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined)
123 JSValue argument0 = exec->argument(0);
124 if (argument0.isUndefined()) {
129 double asDouble = argument0.toInteger(exec);
130 if (asDouble < low || asDouble > high)
133 result = static_cast<int>(asDouble);
137 // The largest finite floating point number is 1.mantissa * 2^(0x7fe-0x3ff).
138 // Since 2^N in binary is a one bit followed by N zero bits. 1 * 2^3ff requires
139 // at most 1024 characters to the left of a decimal point, in base 2 (1025 if
140 // we include a minus sign). For the fraction, a value with an exponent of 0
141 // has up to 52 bits to the right of the decimal point. Each decrement of the
142 // exponent down to a minimum of -0x3fe adds an additional digit to the length
143 // of the fraction. As such the maximum fraction size is 1075 (1076 including
144 // a point). We pick a buffer size such that can simply place the point in the
145 // center of the buffer, and are guaranteed to have enough space in each direction
146 // fo any number of digits an IEEE number may require to represent.
147 typedef char RadixBuffer[2180];
149 // Mapping from integers 0..35 to digit identifying this value, for radix 2..36.
150 static const char* const radixDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
152 static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
154 ASSERT(isfinite(number));
155 ASSERT(radix >= 2 && radix <= 36);
157 // Position the decimal point at the center of the string, set
158 // the startOfResultString pointer to point at the decimal point.
159 char* decimalPoint = buffer + sizeof(buffer) / 2;
160 char* startOfResultString = decimalPoint;
163 bool isNegative = number < 0;
166 double integerPart = floor(number);
168 // We use this to test for odd values in odd radix bases.
169 // Where the base is even, (e.g. 10), to determine whether a value is even we need only
170 // consider the least significant digit. For example, 124 in base 10 is even, because '4'
171 // is even. if the radix is odd, then the radix raised to an integer power is also odd.
172 // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
173 // is multiplied by an odd number, the result is even if the sum of all digits is even.
175 // For the integer portion of the result, we only need test whether the integer value is
176 // even or odd. For each digit of the fraction added, we should invert our idea of whether
177 // the number is odd if the new digit is odd.
179 // Also initialize digit to this value; for even radix values we only need track whether
180 // the last individual digit was odd.
181 bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
182 ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
183 bool isOddInOddRadix = integerPartIsOdd;
184 uint32_t digit = integerPartIsOdd;
186 // Check if the value has a fractional part to convert.
187 double fractionPart = number - integerPart;
189 // Write the decimal point now.
192 // Higher precision representation of the fractional part.
193 Uint16WithFraction fraction(fractionPart);
195 bool needsRoundingUp = false;
196 char* endOfResultString = decimalPoint + 1;
198 // Calculate the delta from the current number to the next & previous possible IEEE numbers.
199 double nextNumber = nextafter(number, std::numeric_limits<double>::infinity());
200 double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity());
201 ASSERT(isfinite(nextNumber) && !signbit(nextNumber));
202 ASSERT(isfinite(lastNumber) && !signbit(lastNumber));
203 double deltaNextDouble = nextNumber - number;
204 double deltaLastDouble = number - lastNumber;
205 ASSERT(isfinite(deltaNextDouble) && !signbit(deltaNextDouble));
206 ASSERT(isfinite(deltaLastDouble) && !signbit(deltaLastDouble));
208 // We track the delta from the current value to the next, to track how many digits of the
209 // fraction we need to write. For example, if the value we are converting is precisely
210 // 1.2345, so far we have written the digits "1.23" to a string leaving a remainder of
211 // 0.45, and we want to determine whether we can round off, or whether we need to keep
212 // appending digits ('4'). We can stop adding digits provided that then next possible
213 // lower IEEE value is further from 1.23 than the remainder we'd be rounding off (0.45),
214 // which is to say, less than 1.2255. Put another way, the delta between the prior
215 // possible value and this number must be more than 2x the remainder we'd be rounding off
216 // (or more simply half the delta between numbers must be greater than the remainder).
218 // Similarly we need track the delta to the next possible value, to dertermine whether
219 // to round up. In almost all cases (other than at exponent boundaries) the deltas to
220 // prior and subsequent values are identical, so we don't need track then separately.
221 if (deltaNextDouble != deltaLastDouble) {
222 // Since the deltas are different track them separately. Pre-multiply by 0.5.
223 Uint16WithFraction halfDeltaNext(deltaNextDouble, 1);
224 Uint16WithFraction halfDeltaLast(deltaLastDouble, 1);
227 // examine the remainder to determine whether we should be considering rounding
228 // up or down. If remainder is precisely 0.5 rounding is to even.
229 int dComparePoint5 = fraction.comparePoint5();
230 if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
231 // Check for rounding up; are we closer to the value we'd round off to than
232 // the next IEEE value would be?
233 if (fraction.sumGreaterThanOne(halfDeltaNext)) {
234 needsRoundingUp = true;
238 // Check for rounding down; are we closer to the value we'd round off to than
239 // the prior IEEE value would be?
240 if (fraction < halfDeltaLast)
244 ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
245 // Write a digit to the string.
247 digit = fraction.floorAndSubtract();
248 *endOfResultString++ = radixDigits[digit];
249 // Keep track whether the portion written is currently even, if the radix is odd.
251 isOddInOddRadix = !isOddInOddRadix;
253 // Shift the fractions by radix.
254 halfDeltaNext *= radix;
255 halfDeltaLast *= radix;
258 // This code is identical to that above, except since deltaNextDouble != deltaLastDouble
259 // we don't need to track these two values separately.
260 Uint16WithFraction halfDelta(deltaNextDouble, 1);
263 int dComparePoint5 = fraction.comparePoint5();
264 if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
265 if (fraction.sumGreaterThanOne(halfDelta)) {
266 needsRoundingUp = true;
269 } else if (fraction < halfDelta)
272 ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
274 digit = fraction.floorAndSubtract();
276 isOddInOddRadix = !isOddInOddRadix;
277 *endOfResultString++ = radixDigits[digit];
283 // Check if the fraction needs rounding off (flag set in the loop writing digits, above).
284 if (needsRoundingUp) {
285 // Whilst the last digit is the maximum in the current radix, remove it.
286 // e.g. rounding up the last digit in "12.3999" is the same as rounding up the
287 // last digit in "12.3" - both round up to "12.4".
288 while (endOfResultString[-1] == radixDigits[radix - 1])
291 // Radix digits are sequential in ascii/unicode, except for '9' and 'a'.
292 // E.g. the first 'if' case handles rounding 67.89 to 67.8a in base 16.
293 // The 'else if' case handles rounding of all other digits.
294 if (endOfResultString[-1] == '9')
295 endOfResultString[-1] = 'a';
296 else if (endOfResultString[-1] != '.')
297 ++endOfResultString[-1];
299 // One other possibility - there may be no digits to round up in the fraction
300 // (or all may be been rounded off already), in which case we may need to
301 // round into the integer portion of the number. Remove the decimal point.
303 // In order to get here there must have been a non-zero fraction, in which case
304 // there must be at least one bit of the value's mantissa not in use in the
305 // integer part of the number. As such, adding to the integer part should not
306 // be able to lose precision.
307 ASSERT((integerPart + 1) - integerPart == 1);
311 // We only need to check for trailing zeros if the value does not get rounded up.
312 while (endOfResultString[-1] == '0')
316 *endOfResultString = '\0';
317 ASSERT(endOfResultString < buffer + sizeof(buffer));
319 *decimalPoint = '\0';
321 BigInteger units(integerPart);
323 // Always loop at least once, to emit at least '0'.
325 ASSERT(buffer < startOfResultString);
327 // Read a single digit and write it to the front of the string.
328 // Divide by radix to remove one digit from the value.
329 digit = units.divide(radix);
330 *--startOfResultString = radixDigits[digit];
333 // If the number is negative, prepend '-'.
335 *--startOfResultString = '-';
336 ASSERT(buffer <= startOfResultString);
338 return startOfResultString;
341 // toExponential converts a number to a string, always formatting as an expoential.
342 // This method takes an optional argument specifying a number of *decimal places*
343 // to round the significand to (or, put another way, this method optionally rounds
344 // to argument-plus-one significant figures).
345 EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
348 if (!toThisNumber(exec->hostThisValue(), x))
349 return throwVMTypeError(exec);
352 int decimalPlacesInExponent;
354 if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined))
355 return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20"));
357 // Handle NaN and Infinity.
359 return JSValue::encode(jsString(exec, UString::number(x)));
361 // Round if the argument is not undefined, always format as exponential.
362 char buffer[WTF::NumberToStringBufferLength];
363 DoubleConversionStringBuilder builder(buffer, WTF::NumberToStringBufferLength);
364 const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter();
367 ? converter.ToExponential(x, -1, &builder)
368 : converter.ToExponential(x, decimalPlacesInExponent, &builder);
369 return JSValue::encode(jsString(exec, UString(builder.Finalize())));
372 // toFixed converts a number to a string, always formatting as an a decimal fraction.
373 // This method takes an argument specifying a number of decimal places to round the
374 // significand to. However when converting large values (1e+21 and above) this
375 // method will instead fallback to calling ToString.
376 EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
379 if (!toThisNumber(exec->hostThisValue(), x))
380 return throwVMTypeError(exec);
384 bool isUndefined; // This is ignored; undefined treated as 0.
385 if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
386 return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20"));
388 // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
389 // This also covers Ininity, and structure the check so that NaN
390 // values are also handled by numberToString
391 if (!(fabs(x) < 1e+21))
392 return JSValue::encode(jsString(exec, UString::number(x)));
394 // The check above will return false for NaN or Infinity, these will be
395 // handled by numberToString.
398 NumberToStringBuffer buffer;
399 return JSValue::encode(jsString(exec, UString(numberToFixedWidthString(x, decimalPlaces, buffer))));
402 // toPrecision converts a number to a string, takeing an argument specifying a
403 // number of significant figures to round the significand to. For positive
404 // exponent, all values that can be represented using a decimal fraction will
405 // be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
406 // decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
407 // For negative exponents values >= 1e-6 are formated as decimal fractions,
408 // with smaller values converted to exponential representation.
409 EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
412 if (!toThisNumber(exec->hostThisValue(), x))
413 return throwVMTypeError(exec);
416 int significantFigures;
418 if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
419 return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21"));
421 // To precision called with no argument is treated as ToString.
423 return JSValue::encode(jsString(exec, UString::number(x)));
425 // Handle NaN and Infinity.
427 return JSValue::encode(jsString(exec, UString::number(x)));
429 NumberToStringBuffer buffer;
430 return JSValue::encode(jsString(exec, UString(numberToFixedPrecisionString(x, significantFigures, buffer))));
433 EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
436 if (!toThisNumber(exec->hostThisValue(), x))
437 return throwVMTypeError(exec);
439 JSValue radixValue = exec->argument(0);
441 if (radixValue.isInt32())
442 radix = radixValue.asInt32();
443 else if (radixValue.isUndefined())
446 radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0
449 return JSValue::encode(jsString(exec, jsNumber(x).toString(exec)));
451 // Fast path for number to character conversion.
453 unsigned c = static_cast<unsigned>(x);
454 if (c == x && c < 36) {
455 JSGlobalData* globalData = &exec->globalData();
456 return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, radixDigits[c]));
460 if (radix < 2 || radix > 36)
461 return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));
464 return JSValue::encode(jsString(exec, UString::number(x)));
467 return JSValue::encode(jsString(exec, toStringWithRadix(s, x, radix)));
470 EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
473 if (!toThisNumber(exec->hostThisValue(), x))
474 return throwVMTypeError(exec);
476 return JSValue::encode(jsString(exec, jsNumber(x).toString(exec)));
479 EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
482 if (!toThisNumber(exec->hostThisValue(), x))
483 return throwVMTypeError(exec);
484 return JSValue::encode(jsNumber(x));