1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3
* ***** BEGIN LICENSE BLOCK *****
4
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 1.1 (the "License"); you may not use this file except in compliance with
8
* the License. You may obtain a copy of the License at
9
* http://www.mozilla.org/MPL/
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
16
* The Original Code is Mozilla Communicator client code, released
19
* The Initial Developer of the Original Code is
20
* Netscape Communications Corporation.
21
* Portions created by the Initial Developer are Copyright (C) 1998
22
* the Initial Developer. All Rights Reserved.
27
* Alternatively, the contents of this file may be used under the terms of
28
* either of the GNU General Public License Version 2 or later (the "GPL"),
29
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30
* in which case the provisions of the GPL or the LGPL are applicable instead
31
* of those above. If you wish to allow use of your version of this file only
32
* under the terms of either the GPL or the LGPL, and not to allow others to
33
* use your version of this file under the terms of the MPL, indicate your
34
* decision by deleting the provisions above and replace them with the notice
35
* and other provisions required by the GPL or the LGPL. If you do not delete
36
* the provisions above, a recipient may use your version of this file under
37
* the terms of any one of the MPL, the GPL or the LGPL.
39
* ***** END LICENSE BLOCK ***** */
42
* JS number type and wrapper class.
45
#if defined(XP_WIN) || defined(XP_OS2)
52
#include "jsutil.h" /* Added by JSIFY */
67
num_isNaN(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
71
if (!js_ValueToNumber(cx, argv[0], &x))
73
*rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
78
num_isFinite(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
82
if (!js_ValueToNumber(cx, argv[0], &x))
84
*rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
89
num_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
93
const jschar *bp, *ep;
95
str = js_ValueToString(cx, argv[0]);
98
/* XXXbe js_strtod shouldn't require NUL termination */
99
bp = js_UndependString(cx, str);
102
if (!js_strtod(cx, bp, &ep, &d))
105
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
108
return js_NewNumberValue(cx, d, rval);
111
/* See ECMA 15.1.2.2. */
113
num_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
118
const jschar *bp, *ep;
120
str = js_ValueToString(cx, argv[0]);
125
if (!js_ValueToECMAInt32(cx, argv[1], &radix))
130
if (radix != 0 && (radix < 2 || radix > 36)) {
131
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
134
/* XXXbe js_strtointeger shouldn't require NUL termination */
135
bp = js_UndependString(cx, str);
138
if (!js_strtointeger(cx, bp, &ep, radix, &d))
141
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
144
return js_NewNumberValue(cx, d, rval);
147
const char js_Infinity_str[] = "Infinity";
148
const char js_NaN_str[] = "NaN";
149
const char js_isNaN_str[] = "isNaN";
150
const char js_isFinite_str[] = "isFinite";
151
const char js_parseFloat_str[] = "parseFloat";
152
const char js_parseInt_str[] = "parseInt";
154
static JSFunctionSpec number_functions[] = {
155
{"isNaN", num_isNaN, 1,0,0},
156
{"isFinite", num_isFinite, 1,0,0},
157
{"parseFloat", num_parseFloat, 1,0,0},
158
{"parseInt", num_parseInt, 2,0,0},
162
static JSClass number_class = {
165
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
166
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
167
JSCLASS_NO_OPTIONAL_MEMBERS
171
Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
177
if (!js_ValueToNumber(cx, argv[0], &d))
182
if (!js_NewNumberValue(cx, d, &v))
184
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
188
OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
194
num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
198
char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
202
if (!JS_InstanceOf(cx, obj, &number_class, argv))
204
v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
205
JS_ASSERT(JSVAL_IS_NUMBER(v));
206
d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
207
numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
209
JS_ReportOutOfMemory(cx);
212
JS_snprintf(buf, sizeof buf, "(new %s(%s))", number_class.name, numStr);
213
str = JS_NewStringCopyZ(cx, buf);
216
*rval = STRING_TO_JSVAL(str);
221
/* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
223
IntToString(jsint i, char *buf, size_t bufSize)
228
u = (i < 0) ? -i : i;
230
cp = buf + bufSize; /* one past last buffer cell */
231
*--cp = '\0'; /* null terminate the string to be */
234
* Build the string from behind. We use multiply and subtraction
235
* instead of modulus because that's much faster.
238
jsuint newu = u / 10;
239
*--cp = (char)(u - newu * 10) + '0';
250
num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
257
if (!JS_InstanceOf(cx, obj, &number_class, argv))
259
v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
260
JS_ASSERT(JSVAL_IS_NUMBER(v));
261
d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
264
if (!js_ValueToECMAInt32(cx, argv[0], &base))
266
if (base < 2 || base > 36) {
268
char *numStr = IntToString(base, numBuf, sizeof numBuf);
269
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
275
str = js_NumberToString(cx, d);
277
char *dStr = JS_dtobasestr(base, d);
279
JS_ReportOutOfMemory(cx);
282
str = JS_NewStringCopyZ(cx, dStr);
287
*rval = STRING_TO_JSVAL(str);
292
num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
293
jsval *argv, jsval *rval)
296
* For now, forcibly ignore the first (or any) argument and return toString().
297
* ECMA allows this, although it doesn't 'encourage it'.
298
* [The first argument is being reserved by ECMA and we don't want it confused
301
return num_toString(cx, obj, 0, argv, rval);
305
num_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
307
if (!JS_InstanceOf(cx, obj, &number_class, argv))
309
*rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
314
#if JS_HAS_NUMBER_FORMATS
315
#define MAX_PRECISION 100
318
num_to(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, JSDToStrMode zeroArgMode,
319
JSDToStrMode oneArgMode, jsint precisionMin, jsint precisionMax, jsint precisionOffset)
322
jsdouble d, precision;
324
char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)], *numStr; /* Use MAX_PRECISION+1 because precisionOffset can be 1 */
326
if (!JS_InstanceOf(cx, obj, &number_class, argv))
328
v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
329
JS_ASSERT(JSVAL_IS_NUMBER(v));
330
d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
332
if (JSVAL_IS_VOID(argv[0])) {
334
oneArgMode = zeroArgMode;
336
if (!js_ValueToNumber(cx, argv[0], &precision))
338
precision = js_DoubleToInteger(precision);
339
if (precision < precisionMin || precision > precisionMax) {
340
numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
342
JS_ReportOutOfMemory(cx);
344
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
349
numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
351
JS_ReportOutOfMemory(cx);
354
str = JS_NewStringCopyZ(cx, numStr);
357
*rval = STRING_TO_JSVAL(str);
362
num_toFixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
364
/* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
365
return num_to(cx, obj, argc, argv, rval, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0);
369
num_toExponential(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
371
/* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
372
return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1);
376
num_toPrecision(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
378
/* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
379
return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0);
381
#endif /* JS_HAS_NUMBER_FORMATS */
384
static JSFunctionSpec number_methods[] = {
386
{js_toSource_str, num_toSource, 0,0,0},
388
{js_toString_str, num_toString, 0,0,0},
389
{js_toLocaleString_str, num_toLocaleString, 0,0,0},
390
{js_valueOf_str, num_valueOf, 0,0,0},
391
#if JS_HAS_NUMBER_FORMATS
392
{"toFixed", num_toFixed, 1,0,0},
393
{"toExponential", num_toExponential, 1,0,0},
394
{"toPrecision", num_toPrecision, 1,0,0},
399
/* NB: Keep this in synch with number_constants[]. */
402
NC_POSITIVE_INFINITY,
403
NC_NEGATIVE_INFINITY,
410
* Some to most C compilers forbid spelling these at compile time, or barf
411
* if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
412
* using union jsdpun.
414
static JSConstDoubleSpec number_constants[] = {
415
{0, js_NaN_str, 0,{0,0,0}},
416
{0, "POSITIVE_INFINITY", 0,{0,0,0}},
417
{0, "NEGATIVE_INFINITY", 0,{0,0,0}},
418
{1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
419
{0, "MIN_VALUE", 0,{0,0,0}},
426
#if defined XP_WIN && \
427
!defined __MWERKS__ && \
428
(defined _M_IX86 || \
429
(defined __GNUC__ && !defined __MINGW32__))
432
* Set the exception mask to mask all exceptions and set the FPU precision
433
* to 53 bit mantissa.
434
* On Alpha platform this is handled via Compiler option.
436
#define FIX_FPU() _control87(MCW_EM | PC_53, MCW_EM | MCW_PC)
440
#define FIX_FPU() ((void)0)
445
js_InitRuntimeNumberState(JSContext *cx)
451
JS_ASSERT(!rt->jsNaN);
455
u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
457
number_constants[NC_NaN].dval = NaN = u.d;
458
rt->jsNaN = js_NewDouble(cx, NaN);
459
if (!rt->jsNaN || !js_LockGCThing(cx, rt->jsNaN))
462
u.s.hi = JSDOUBLE_HI32_EXPMASK;
464
number_constants[NC_POSITIVE_INFINITY].dval = u.d;
465
rt->jsPositiveInfinity = js_NewDouble(cx, u.d);
466
if (!rt->jsPositiveInfinity ||
467
!js_LockGCThing(cx, rt->jsPositiveInfinity)) {
471
u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
473
number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
474
rt->jsNegativeInfinity = js_NewDouble(cx, u.d);
475
if (!rt->jsNegativeInfinity ||
476
!js_LockGCThing(cx, rt->jsNegativeInfinity)) {
482
number_constants[NC_MIN_VALUE].dval = u.d;
488
js_FinishRuntimeNumberState(JSContext *cx)
490
JSRuntime *rt = cx->runtime;
492
js_UnlockGCThingRT(rt, rt->jsNaN);
493
js_UnlockGCThingRT(rt, rt->jsNegativeInfinity);
494
js_UnlockGCThingRT(rt, rt->jsPositiveInfinity);
497
rt->jsNegativeInfinity = NULL;
498
rt->jsPositiveInfinity = NULL;
502
js_InitNumberClass(JSContext *cx, JSObject *obj)
504
JSObject *proto, *ctor;
507
/* XXX must do at least once per new thread, so do it per JSContext... */
510
if (!JS_DefineFunctions(cx, obj, number_functions))
513
proto = JS_InitClass(cx, obj, NULL, &number_class, Number, 1,
514
NULL, number_methods, NULL, NULL);
515
if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
517
OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE, JSVAL_ZERO);
518
if (!JS_DefineConstDoubles(cx, ctor, number_constants))
523
if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN),
524
NULL, NULL, JSPROP_PERMANENT)) {
529
if (!JS_DefineProperty(cx, obj, js_Infinity_str,
530
DOUBLE_TO_JSVAL(rt->jsPositiveInfinity),
531
NULL, NULL, JSPROP_PERMANENT)) {
538
js_NewDouble(JSContext *cx, jsdouble d)
542
dp = (jsdouble *) js_AllocGCThing(cx, GCX_DOUBLE);
550
js_FinalizeDouble(JSContext *cx, jsdouble *dp)
556
js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
560
dp = js_NewDouble(cx, d);
563
*rval = DOUBLE_TO_JSVAL(dp);
568
js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
575
if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
576
*rval = INT_TO_JSVAL(i);
579
ok = js_NewDoubleValue(cx, d, rval);
587
js_NumberToObject(JSContext *cx, jsdouble d)
592
obj = js_NewObject(cx, &number_class, NULL, NULL);
595
if (!js_NewNumberValue(cx, d, &v)) {
596
cx->newborn[GCX_OBJECT] = NULL;
599
OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
604
js_NumberToString(JSContext *cx, jsdouble d)
607
char buf[DTOSTR_STANDARD_BUFFER_SIZE];
610
if (JSDOUBLE_IS_INT(d, i))
611
numStr = IntToString(i, buf, sizeof buf);
613
numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, d);
615
JS_ReportOutOfMemory(cx);
619
return JS_NewStringCopyZ(cx, numStr);
623
js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
627
const jschar *bp, *ep;
629
if (JSVAL_IS_OBJECT(v)) {
630
obj = JSVAL_TO_OBJECT(v);
635
if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &v))
638
if (JSVAL_IS_INT(v)) {
639
*dp = (jsdouble)JSVAL_TO_INT(v);
640
} else if (JSVAL_IS_DOUBLE(v)) {
641
*dp = *JSVAL_TO_DOUBLE(v);
642
} else if (JSVAL_IS_STRING(v)) {
643
str = JSVAL_TO_STRING(v);
645
* Note that ECMA doesn't treat a string beginning with a '0' as an
646
* octal number here. This works because all such numbers will be
647
* interpreted as decimal by js_strtod and will never get passed to
648
* js_strtointeger (which would interpret them as octal).
650
/* XXXbe js_strtod shouldn't require NUL termination */
651
bp = js_UndependString(cx, str);
654
if ((!js_strtod(cx, bp, &ep, dp) ||
655
js_SkipWhiteSpace(ep) != bp + str->length) &&
656
(!js_strtointeger(cx, bp, &ep, 0, dp) ||
657
js_SkipWhiteSpace(ep) != bp + str->length)) {
660
} else if (JSVAL_IS_BOOLEAN(v)) {
661
*dp = JSVAL_TO_BOOLEAN(v) ? 1 : 0;
663
#if JS_BUG_FALLIBLE_TONUM
664
str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
667
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NAN,
668
JS_GetStringBytes(str));
674
*dp = *cx->runtime->jsNaN;
681
js_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
685
if (!js_ValueToNumber(cx, v, &d))
687
return js_DoubleToECMAInt32(cx, d, ip);
691
js_DoubleToECMAInt32(JSContext *cx, jsdouble d, int32 *ip)
693
jsdouble two32 = 4294967296.0;
694
jsdouble two31 = 2147483648.0;
696
if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
701
d = (d >= 0) ? floor(d) : ceil(d) + two32;
703
*ip = (int32)(d - two32);
710
js_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
714
if (!js_ValueToNumber(cx, v, &d))
716
return js_DoubleToECMAUint32(cx, d, ip);
720
js_DoubleToECMAUint32(JSContext *cx, jsdouble d, uint32 *ip)
723
jsdouble two32 = 4294967296.0;
725
if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
731
d = floor(neg ? -d : d);
736
d = (d >= 0) ? d : d + two32;
742
js_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
747
if (JSVAL_IS_INT(v)) {
748
*ip = JSVAL_TO_INT(v);
751
if (!js_ValueToNumber(cx, v, &d))
753
if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
754
str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
756
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
757
JSMSG_CANT_CONVERT, JS_GetStringBytes(str));
762
*ip = (int32)floor(d + 0.5); /* Round to nearest */
767
js_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
773
if (!js_ValueToNumber(cx, v, &d))
775
if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
780
if ((jsdouble)i == d) {
785
d = floor(neg ? -d : d);
788
d = fmod(d, (double)m);
796
js_DoubleToInteger(jsdouble d)
802
if (!JSDOUBLE_IS_FINITE(d)) {
803
if (JSDOUBLE_IS_NaN(d))
808
d = floor(neg ? -d : d);
814
js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp)
818
char *cstr, *istr, *estr;
821
const jschar *s1 = js_SkipWhiteSpace(s);
822
size_t length = js_strlen(s1);
824
/* Use cbuf to avoid malloc */
825
if (length >= sizeof cbuf) {
826
cstr = (char *) JS_malloc(cx, length + 1);
833
for (i = 0; i <= length; i++) {
838
cstr[i] = (char)s1[i];
842
if ((negative = (*istr == '-')) != 0 || *istr == '+')
844
if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
845
d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
849
d = JS_strtod(cstr, &estr, &err);
850
if (err == JS_DTOA_ENOMEM) {
851
JS_ReportOutOfMemory(cx);
856
if (err == JS_DTOA_ERANGE) {
858
d = *cx->runtime->jsPositiveInfinity;
859
else if (d == -HUGE_VAL)
860
d = *cx->runtime->jsNegativeInfinity;
863
if (d == 0.0 && negative) {
865
* "-0", "-1e-2000" come out as positive zero
866
* here on HPUX. Force a negative zero instead.
868
JSDOUBLE_HI32(d) = JSDOUBLE_HI32_SIGNBIT;
869
JSDOUBLE_LO32(d) = 0;
877
*ep = i ? s1 + i : s;
882
struct BinaryDigitReader
884
uintN base; /* Base of number; must be a power of 2 */
885
uintN digit; /* Current digit value in radix given by base */
886
uintN digitMask; /* Mask to extract the next bit from digit */
887
const jschar *digits; /* Pointer to the remaining digits */
888
const jschar *end; /* Pointer to first non-digit */
891
/* Return the next binary digit from the number or -1 if done */
892
static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr)
896
if (bdr->digitMask == 0) {
899
if (bdr->digits == bdr->end)
903
if ('0' <= c && c <= '9')
904
bdr->digit = c - '0';
905
else if ('a' <= c && c <= 'z')
906
bdr->digit = c - 'a' + 10;
907
else bdr->digit = c - 'A' + 10;
908
bdr->digitMask = bdr->base >> 1;
910
bit = (bdr->digit & bdr->digitMask) != 0;
911
bdr->digitMask >>= 1;
916
js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, jsdouble *dp)
921
const jschar *s1 = js_SkipWhiteSpace(s);
923
if ((negative = (*s1 == '-')) != 0 || *s1 == '+')
927
/* No base supplied, or some base that evaluated to 0. */
929
/* It's either hex or octal; only increment char if str isn't '0' */
930
if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */
937
base = 10; /* Default to decimal. */
939
} else if (base == 16 && *s1 == '0' && (s1[1] == 'X' || s1[1] == 'x')) {
940
/* If base is 16, ignore hex prefix. */
945
* Done with the preliminaries; find some prefix of the string that's
946
* a number in the given base.
948
start = s1; /* Mark - if string is empty, we return NaN. */
953
if ('0' <= c && c <= '9')
955
else if ('a' <= c && c <= 'z')
956
digit = c - 'a' + 10;
957
else if ('A' <= c && c <= 'Z')
958
digit = c - 'A' + 10;
961
if (digit >= (uintN)base)
963
value = value * base + digit;
967
if (value >= 9007199254740992.0) {
970
* If we're accumulating a decimal number and the number is >=
971
* 2^53, then the result from the repeated multiply-add above may
972
* be inaccurate. Call JS_strtod to get the correct answer.
975
size_t length = s1 - start;
976
char *cstr = (char *) JS_malloc(cx, length + 1);
982
for (i = 0; i != length; i++)
983
cstr[i] = (char)start[i];
986
value = JS_strtod(cstr, &estr, &err);
987
if (err == JS_DTOA_ENOMEM) {
988
JS_ReportOutOfMemory(cx);
992
if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
993
value = *cx->runtime->jsPositiveInfinity;
995
} else if ((base & (base - 1)) == 0) {
997
* The number may also be inaccurate for power-of-two bases. This
998
* happens if the addition in value * base + digit causes a round-
999
* down to an even least significant mantissa bit when the first
1000
* dropped bit is a one. If any of the following digits in the
1001
* number (which haven't been added in yet) are nonzero, then the
1002
* correct action would have been to round up instead of down. An
1003
* example occurs when reading the number 0x1000000000000081, which
1004
* rounds to 0x1000000000000000 instead of 0x1000000000000100.
1006
struct BinaryDigitReader bdr;
1016
/* Skip leading zeros. */
1018
bit = GetNextBinaryDigit(&bdr);
1022
/* Gather the 53 significant bits (including the leading 1) */
1024
for (j = 52; j; j--) {
1025
bit = GetNextBinaryDigit(&bdr);
1028
value = value*2 + bit;
1030
/* bit2 is the 54th bit (the first dropped from the mantissa) */
1031
bit2 = GetNextBinaryDigit(&bdr);
1033
jsdouble factor = 2.0;
1034
intN sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
1037
while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) {
1041
value += bit2 & (bit | sticky);
1048
/* We don't worry about inaccurate numbers for any other base. */
1054
*dp = negative ? -value : value;