679f7479dec7eeb543ee9e62333f06f83d49ef4d
[WebKit-https.git] / Source / JavaScriptCore / runtime / NumberPrototype.cpp
1 /*
2  *  Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
4  *
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.
9  *
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.
14  *
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
18  *  USA
19  *
20  */
21
22 #include "config.h"
23 #include "NumberPrototype.h"
24
25 #include "BigInteger.h"
26 #include "Error.h"
27 #include "JSFunction.h"
28 #include "JSString.h"
29 #include "Operations.h"
30 #include "Uint16WithFraction.h"
31 #include "dtoa.h"
32 #include <wtf/Assertions.h>
33 #include <wtf/DecimalNumber.h>
34 #include <wtf/MathExtras.h>
35 #include <wtf/Vector.h>
36
37 namespace JSC {
38
39 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);
40 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*);
41 static EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*);
42 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*);
43 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*);
44 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
45
46 }
47
48 #include "NumberPrototype.lut.h"
49
50 namespace JSC {
51
52 const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable };
53
54 /* Source for NumberPrototype.lut.h
55 @begin numberPrototypeTable
56   toString          numberProtoFuncToString         DontEnum|Function 1
57   toLocaleString    numberProtoFuncToLocaleString   DontEnum|Function 0
58   valueOf           numberProtoFuncValueOf          DontEnum|Function 0
59   toFixed           numberProtoFuncToFixed          DontEnum|Function 1
60   toExponential     numberProtoFuncToExponential    DontEnum|Function 1
61   toPrecision       numberProtoFuncToPrecision      DontEnum|Function 1
62 @end
63 */
64
65 ASSERT_CLASS_FITS_IN_CELL(NumberPrototype);
66
67 NumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
68     : NumberObject(exec->globalData(), structure)
69 {
70     setInternalValue(exec->globalData(), jsNumber(0));
71
72     ASSERT(inherits(&s_info));
73     putAnonymousValue(globalObject->globalData(), 0, globalObject);
74 }
75
76 bool NumberPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
77 {
78     return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec), this, propertyName, slot);
79 }
80
81 bool NumberPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
82 {
83     return getStaticFunctionDescriptor<NumberObject>(exec, ExecState::numberPrototypeTable(exec), this, propertyName, descriptor);
84 }
85
86 // ------------------------------ Functions ---------------------------
87
88 static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double &x)
89 {
90     JSValue v = thisValue.getJSNumber();
91     if (UNLIKELY(!v))
92         return false;
93     x = v.uncheckedGetNumber();
94     return true;
95 }
96
97 static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined)
98 {
99     result = 0;
100     isUndefined = false;
101
102     JSValue argument0 = exec->argument(0);
103     if (argument0.isUndefined()) {
104         isUndefined = true;
105         return true;
106     }
107
108     double asDouble = argument0.toInteger(exec);
109     if (asDouble < low || asDouble > high)
110         return false;
111
112     result = static_cast<int>(asDouble);
113     return true;
114 }
115
116 // The largest finite floating point number is 1.mantissa * 2^(0x7fe-0x3ff).
117 // Since 2^N in binary is a one bit followed by N zero bits. 1 * 2^3ff requires
118 // at most 1024 characters to the left of a decimal point, in base 2 (1025 if
119 // we include a minus sign). For the fraction, a value with an exponent of 0
120 // has up to 52 bits to the right of the decimal point. Each decrement of the
121 // exponent down to a minimum of -0x3fe adds an additional digit to the length
122 // of the fraction. As such the maximum fraction size is 1075 (1076 including
123 // a point). We pick a buffer size such that can simply place the point in the
124 // center of the buffer, and are guaranteed to have enough space in each direction
125 // fo any number of digits an IEEE number may require to represent.
126 typedef char RadixBuffer[2180];
127
128 // Mapping from integers 0..35 to digit identifying this value, for radix 2..36.
129 static const char* const radixDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
130
131 static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
132 {
133     ASSERT(isfinite(number));
134     ASSERT(radix >= 2 && radix <= 36);
135
136     // Position the decimal point at the center of the string, set
137     // the startOfResultString pointer to point at the decimal point.
138     char* decimalPoint = buffer + sizeof(buffer) / 2;
139     char* startOfResultString = decimalPoint;
140
141     // Extract the sign.
142     bool isNegative = number < 0;
143     if (signbit(number))
144         number = -number;
145     double integerPart = floor(number);
146
147     // We use this to test for odd values in odd radix bases.
148     // Where the base is even, (e.g. 10), to determine whether a value is even we need only
149     // consider the least significant digit. For example, 124 in base 10 is even, because '4'
150     // is even. if the radix is odd, then the radix raised to an integer power is also odd.
151     // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
152     // is multiplied by an odd number, the result is even if the sum of all digits is even.
153     //
154     // For the integer portion of the result, we only need test whether the integer value is
155     // even or odd. For each digit of the fraction added, we should invert our idea of whether
156     // the number is odd if the new digit is odd.
157     //
158     // Also initialize digit to this value; for even radix values we only need track whether
159     // the last individual digit was odd.
160     bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
161     ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
162     bool isOddInOddRadix = integerPartIsOdd;
163     uint32_t digit = integerPartIsOdd;
164
165     // Check if the value has a fractional part to convert.
166     double fractionPart = number - integerPart;
167     if (fractionPart) {
168         // Write the decimal point now.
169         *decimalPoint = '.';
170
171         // Higher precision representation of the fractional part.
172         Uint16WithFraction fraction(fractionPart);
173
174         bool needsRoundingUp = false;
175         char* endOfResultString = decimalPoint + 1;
176
177         // Calculate the delta from the current number to the next & previous possible IEEE numbers.
178         double nextNumber = nextafter(number, std::numeric_limits<double>::infinity());
179         double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity());
180         ASSERT(isfinite(nextNumber) && !signbit(nextNumber));
181         ASSERT(isfinite(lastNumber) && !signbit(lastNumber));
182         double deltaNextDouble = nextNumber - number;
183         double deltaLastDouble = number - lastNumber;
184         ASSERT(isfinite(deltaNextDouble) && !signbit(deltaNextDouble));
185         ASSERT(isfinite(deltaLastDouble) && !signbit(deltaLastDouble));
186
187         // We track the delta from the current value to the next, to track how many digits of the
188         // fraction we need to write. For example, if the value we are converting is precisely
189         // 1.2345, so far we have written the digits "1.23" to a string leaving a remainder of
190         // 0.45, and we want to determine whether we can round off, or whether we need to keep
191         // appending digits ('4'). We can stop adding digits provided that then next possible
192         // lower IEEE value is further from 1.23 than the remainder we'd be rounding off (0.45),
193         // which is to say, less than 1.2255. Put another way, the delta between the prior
194         // possible value and this number must be more than 2x the remainder we'd be rounding off
195         // (or more simply half the delta between numbers must be greater than the remainder).
196         //
197         // Similarly we need track the delta to the next possible value, to dertermine whether
198         // to round up. In almost all cases (other than at exponent boundaries) the deltas to
199         // prior and subsequent values are identical, so we don't need track then separately.
200         if (deltaNextDouble != deltaLastDouble) {
201             // Since the deltas are different track them separately. Pre-multiply by 0.5.
202             Uint16WithFraction halfDeltaNext(deltaNextDouble, 1);
203             Uint16WithFraction halfDeltaLast(deltaLastDouble, 1);
204
205             while (true) {
206                 // examine the remainder to determine whether we should be considering rounding
207                 // up or down. If remainder is precisely 0.5 rounding is to even.
208                 int dComparePoint5 = fraction.comparePoint5();
209                 if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
210                     // Check for rounding up; are we closer to the value we'd round off to than
211                     // the next IEEE value would be?
212                     if (fraction.sumGreaterThanOne(halfDeltaNext)) {
213                         needsRoundingUp = true;
214                         break;
215                     }
216                 } else {
217                     // Check for rounding down; are we closer to the value we'd round off to than
218                     // the prior IEEE value would be?
219                     if (fraction < halfDeltaLast)
220                         break;
221                 }
222
223                 ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
224                 // Write a digit to the string.
225                 fraction *= radix;
226                 digit = fraction.floorAndSubtract();
227                 *endOfResultString++ = radixDigits[digit];
228                 // Keep track whether the portion written is currently even, if the radix is odd.
229                 if (digit & 1)
230                     isOddInOddRadix = !isOddInOddRadix;
231
232                 // Shift the fractions by radix.
233                 halfDeltaNext *= radix;
234                 halfDeltaLast *= radix;
235             }
236         } else {
237             // This code is identical to that above, except since deltaNextDouble != deltaLastDouble
238             // we don't need to track these two values separately.
239             Uint16WithFraction halfDelta(deltaNextDouble, 1);
240
241             while (true) {
242                 int dComparePoint5 = fraction.comparePoint5();
243                 if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
244                     if (fraction.sumGreaterThanOne(halfDelta)) {
245                         needsRoundingUp = true;
246                         break;
247                     }
248                 } else if (fraction < halfDelta)
249                     break;
250
251                 ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
252                 fraction *= radix;
253                 digit = fraction.floorAndSubtract();
254                 if (digit & 1)
255                     isOddInOddRadix = !isOddInOddRadix;
256                 *endOfResultString++ = radixDigits[digit];
257
258                 halfDelta *= radix;
259             }
260         }
261
262         // Check if the fraction needs rounding off (flag set in the loop writing digits, above).
263         if (needsRoundingUp) {
264             // Whilst the last digit is the maximum in the current radix, remove it.
265             // e.g. rounding up the last digit in "12.3999" is the same as rounding up the
266             // last digit in "12.3" - both round up to "12.4".
267             while (endOfResultString[-1] == radixDigits[radix - 1])
268                 --endOfResultString;
269
270             // Radix digits are sequential in ascii/unicode, except for '9' and 'a'.
271             // E.g. the first 'if' case handles rounding 67.89 to 67.8a in base 16.
272             // The 'else if' case handles rounding of all other digits.
273             if (endOfResultString[-1] == '9')
274                 endOfResultString[-1] = 'a';
275             else if (endOfResultString[-1] != '.')
276                 ++endOfResultString[-1];
277             else {
278                 // One other possibility - there may be no digits to round up in the fraction
279                 // (or all may be been rounded off already), in which case we may need to
280                 // round into the integer portion of the number. Remove the decimal point.
281                 --endOfResultString;
282                 // In order to get here there must have been a non-zero fraction, in which case
283                 // there must be at least one bit of the value's mantissa not in use in the
284                 // integer part of the number. As such, adding to the integer part should not
285                 // be able to lose precision.
286                 ASSERT((integerPart + 1) - integerPart == 1);
287                 ++integerPart;
288             }
289         } else {
290             // We only need to check for trailing zeros if the value does not get rounded up.
291             while (endOfResultString[-1] == '0')
292                 --endOfResultString;
293         }
294
295         *endOfResultString = '\0';
296         ASSERT(endOfResultString < buffer + sizeof(buffer));
297     } else
298         *decimalPoint = '\0';
299
300     BigInteger units(integerPart);
301
302     // Always loop at least once, to emit at least '0'.
303     do {
304         ASSERT(buffer < startOfResultString);
305
306         // Read a single digit and write it to the front of the string.
307         // Divide by radix to remove one digit from the value.
308         digit = units.divide(radix);
309         *--startOfResultString = radixDigits[digit];
310     } while (!!units);
311
312     // If the number is negative, prepend '-'.
313     if (isNegative)
314         *--startOfResultString = '-';
315     ASSERT(buffer <= startOfResultString);
316
317     return startOfResultString;
318 }
319
320 // toExponential converts a number to a string, always formatting as an expoential.
321 // This method takes an optional argument specifying a number of *decimal places*
322 // to round the significand to (or, put another way, this method optionally rounds
323 // to argument-plus-one significant figures).
324 EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
325 {
326     // Get x (the double value of this, which should be a Number).
327     double x;
328     if (!toThisNumber(exec->hostThisValue(), x))
329         return throwVMTypeError(exec);
330
331     // Get the argument. 
332     int decimalPlacesInExponent;
333     bool isUndefined;
334     if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined))
335         return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20"));
336
337     // Handle NaN and Infinity.
338     if (!isfinite(x))
339         return JSValue::encode(jsString(exec, UString::number(x)));
340
341     // Round if the argument is not undefined, always format as exponential.
342     NumberToStringBuffer buffer;
343     unsigned length = isUndefined
344         ? DecimalNumber(x).toStringExponential(buffer, WTF::NumberToStringBufferLength)
345         : DecimalNumber(x, RoundingSignificantFigures, decimalPlacesInExponent + 1).toStringExponential(buffer, WTF::NumberToStringBufferLength);
346
347     return JSValue::encode(jsString(exec, UString(buffer, length)));
348 }
349
350 // toFixed converts a number to a string, always formatting as an a decimal fraction.
351 // This method takes an argument specifying a number of decimal places to round the
352 // significand to. However when converting large values (1e+21 and above) this
353 // method will instead fallback to calling ToString. 
354 EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
355 {
356     // Get x (the double value of this, which should be a Number).
357     JSValue thisValue = exec->hostThisValue();
358     JSValue v = thisValue.getJSNumber();
359     if (!v)
360         return throwVMTypeError(exec);
361     double x = v.uncheckedGetNumber();
362
363     // Get the argument. 
364     int decimalPlaces;
365     bool isUndefined; // This is ignored; undefined treated as 0.
366     if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
367         return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20"));
368
369     // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
370     // This also covers Ininity, and structure the check so that NaN
371     // values are also handled by numberToString
372     if (!(fabs(x) < 1e+21))
373         return JSValue::encode(jsString(exec, UString::number(x)));
374
375     // The check above will return false for NaN or Infinity, these will be
376     // handled by numberToString.
377     ASSERT(isfinite(x));
378
379     // Convert to decimal with rounding, and format as decimal.
380     NumberToStringBuffer buffer;
381     unsigned length = DecimalNumber(x, RoundingDecimalPlaces, decimalPlaces).toStringDecimal(buffer, WTF::NumberToStringBufferLength);
382     return JSValue::encode(jsString(exec, UString(buffer, length)));
383 }
384
385 // toPrecision converts a number to a string, takeing an argument specifying a
386 // number of significant figures to round the significand to. For positive
387 // exponent, all values that can be represented using a decimal fraction will
388 // be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
389 // decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
390 // For negative exponents values >= 1e-6 are formated as decimal fractions,
391 // with smaller values converted to exponential representation.
392 EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
393 {
394     // Get x (the double value of this, which should be a Number).
395     JSValue thisValue = exec->hostThisValue();
396     JSValue v = thisValue.getJSNumber();
397     if (!v)
398         return throwVMTypeError(exec);
399     double x = v.uncheckedGetNumber();
400
401     // Get the argument. 
402     int significantFigures;
403     bool isUndefined;
404     if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
405         return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21"));
406
407     // To precision called with no argument is treated as ToString.
408     if (isUndefined)
409         return JSValue::encode(jsString(exec, UString::number(x)));
410
411     // Handle NaN and Infinity.
412     if (!isfinite(x))
413         return JSValue::encode(jsString(exec, UString::number(x)));
414
415     // Convert to decimal with rounding.
416     DecimalNumber number(x, RoundingSignificantFigures, significantFigures);
417     // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format
418     // as decimal. Otherwise, format the number as an exponential. Decimal format
419     // demands a minimum of (exponent + 1) digits to represent a number, for example
420     // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c)
421     NumberToStringBuffer buffer;
422     unsigned length = number.exponent() >= -6 && number.exponent() < significantFigures
423         ? number.toStringDecimal(buffer, WTF::NumberToStringBufferLength)
424         : number.toStringExponential(buffer, WTF::NumberToStringBufferLength);
425     return JSValue::encode(jsString(exec, UString(buffer, length)));
426 }
427
428 EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
429 {
430     JSValue thisValue = exec->hostThisValue();
431     JSValue v = thisValue.getJSNumber();
432     if (!v)
433         return throwVMTypeError(exec);
434
435     JSValue radixValue = exec->argument(0);
436     int radix;
437     if (radixValue.isInt32())
438         radix = radixValue.asInt32();
439     else if (radixValue.isUndefined())
440         radix = 10;
441     else
442         radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0
443
444     if (radix == 10)
445         return JSValue::encode(jsString(exec, v.toString(exec)));
446
447     // Fast path for number to character conversion.
448     if (radix == 36) {
449         if (v.isInt32()) {
450             int x = v.asInt32();
451             if (static_cast<unsigned>(x) < 36) { // Exclude negatives
452                 JSGlobalData* globalData = &exec->globalData();
453                 return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, radixDigits[x]));
454             }
455         }
456     }
457
458     if (radix < 2 || radix > 36)
459         return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));
460
461     double x = v.uncheckedGetNumber();
462     if (!isfinite(x))
463         return JSValue::encode(jsString(exec, UString::number(x)));
464
465     RadixBuffer s;
466     return JSValue::encode(jsString(exec, toStringWithRadix(s, x, radix)));
467 }
468
469 EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
470 {
471     JSValue thisValue = exec->hostThisValue();
472     // FIXME: Not implemented yet.
473
474     JSValue v = thisValue.getJSNumber();
475     if (!v)
476         return throwVMTypeError(exec);
477
478     return JSValue::encode(jsString(exec, v.toString(exec)));
479 }
480
481 EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
482 {
483     JSValue thisValue = exec->hostThisValue();
484     JSValue v = thisValue.getJSNumber();
485     if (!v)
486         return throwVMTypeError(exec);
487
488     return JSValue::encode(v);
489 }
490
491 } // namespace JSC