/[jscoverage]/trunk/js/jsnum.cpp
ViewVC logotype

Contents of /trunk/js/jsnum.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 460 - (show annotations)
Sat Sep 26 23:15:22 2009 UTC (9 years, 7 months ago) by siliconforks
File size: 37768 byte(s)
Upgrade to SpiderMonkey from Firefox 3.5.3.

1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
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/
10 *
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
14 * License.
15 *
16 * The Original Code is Mozilla Communicator client code, released
17 * March 31, 1998.
18 *
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.
23 *
24 * Contributor(s):
25 * IBM Corp.
26 *
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.
38 *
39 * ***** END LICENSE BLOCK ***** */
40
41 /*
42 * JS number type and wrapper class.
43 */
44 #include "jsstddef.h"
45 #if defined(XP_WIN) || defined(XP_OS2)
46 #include <float.h>
47 #endif
48 #ifdef XP_OS2
49 #define _PC_53 PC_53
50 #define _MCW_EM MCW_EM
51 #define _MCW_PC MCW_PC
52 #endif
53 #include <locale.h>
54 #include <limits.h>
55 #include <math.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include "jstypes.h"
59 #include "jsutil.h" /* Added by JSIFY */
60 #include "jsapi.h"
61 #include "jsatom.h"
62 #include "jsbuiltins.h"
63 #include "jscntxt.h"
64 #include "jsversion.h"
65 #include "jsdtoa.h"
66 #include "jsgc.h"
67 #include "jsinterp.h"
68 #include "jsnum.h"
69 #include "jsobj.h"
70 #include "jsopcode.h"
71 #include "jsprf.h"
72 #include "jsscope.h"
73 #include "jsstr.h"
74
75 static JSBool
76 num_isNaN(JSContext *cx, uintN argc, jsval *vp)
77 {
78 jsdouble x;
79
80 if (argc == 0) {
81 *vp = JSVAL_TRUE;
82 return JS_TRUE;
83 }
84 x = js_ValueToNumber(cx, &vp[2]);
85 if (JSVAL_IS_NULL(vp[2]))
86 return JS_FALSE;
87 *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
88 return JS_TRUE;
89 }
90
91 static JSBool
92 num_isFinite(JSContext *cx, uintN argc, jsval *vp)
93 {
94 jsdouble x;
95
96 if (argc == 0) {
97 *vp = JSVAL_FALSE;
98 return JS_TRUE;
99 }
100 x = js_ValueToNumber(cx, &vp[2]);
101 if (JSVAL_IS_NULL(vp[2]))
102 return JS_FALSE;
103 *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
104 return JS_TRUE;
105 }
106
107 static JSBool
108 num_parseFloat(JSContext *cx, uintN argc, jsval *vp)
109 {
110 JSString *str;
111 jsdouble d;
112 const jschar *bp, *end, *ep;
113
114 if (argc == 0) {
115 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
116 return JS_TRUE;
117 }
118 str = js_ValueToString(cx, vp[2]);
119 if (!str)
120 return JS_FALSE;
121 JSSTRING_CHARS_AND_END(str, bp, end);
122 if (!js_strtod(cx, bp, end, &ep, &d))
123 return JS_FALSE;
124 if (ep == bp) {
125 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
126 return JS_TRUE;
127 }
128 return js_NewNumberInRootedValue(cx, d, vp);
129 }
130
131 #ifdef JS_TRACER
132 static jsdouble FASTCALL
133 ParseFloat(JSContext* cx, JSString* str)
134 {
135 const jschar* bp;
136 const jschar* end;
137 const jschar* ep;
138 jsdouble d;
139
140 JSSTRING_CHARS_AND_END(str, bp, end);
141 if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
142 return js_NaN;
143 return d;
144 }
145 #endif
146
147 /* See ECMA 15.1.2.2. */
148 static JSBool
149 num_parseInt(JSContext *cx, uintN argc, jsval *vp)
150 {
151 jsint radix;
152 JSString *str;
153 jsdouble d;
154 const jschar *bp, *end, *ep;
155
156 if (argc == 0) {
157 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
158 return JS_TRUE;
159 }
160 if (argc > 1) {
161 radix = js_ValueToECMAInt32(cx, &vp[3]);
162 if (JSVAL_IS_NULL(vp[3]))
163 return JS_FALSE;
164 } else {
165 radix = 0;
166 }
167 if (radix != 0 && (radix < 2 || radix > 36)) {
168 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
169 return JS_TRUE;
170 }
171
172 if (JSVAL_IS_INT(vp[2]) && (radix == 0 || radix == 10)) {
173 *vp = vp[2];
174 return JS_TRUE;
175 }
176
177 str = js_ValueToString(cx, vp[2]);
178 if (!str)
179 return JS_FALSE;
180 JSSTRING_CHARS_AND_END(str, bp, end);
181 if (!js_strtointeger(cx, bp, end, &ep, radix, &d))
182 return JS_FALSE;
183 if (ep == bp) {
184 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
185 return JS_TRUE;
186 }
187 return js_NewNumberInRootedValue(cx, d, vp);
188 }
189
190 #ifdef JS_TRACER
191 static jsdouble FASTCALL
192 ParseInt(JSContext* cx, JSString* str)
193 {
194 const jschar* bp;
195 const jschar* end;
196 const jschar* ep;
197 jsdouble d;
198
199 JSSTRING_CHARS_AND_END(str, bp, end);
200 if (!js_strtointeger(cx, bp, end, &ep, 0, &d) || ep == bp)
201 return js_NaN;
202 return d;
203 }
204
205 static jsdouble FASTCALL
206 ParseIntDouble(jsdouble d)
207 {
208 if (!JSDOUBLE_IS_FINITE(d))
209 return js_NaN;
210 return floor(d);
211 }
212 #endif
213
214 const char js_Infinity_str[] = "Infinity";
215 const char js_NaN_str[] = "NaN";
216 const char js_isNaN_str[] = "isNaN";
217 const char js_isFinite_str[] = "isFinite";
218 const char js_parseFloat_str[] = "parseFloat";
219 const char js_parseInt_str[] = "parseInt";
220
221 #ifdef JS_TRACER
222
223 JS_DEFINE_TRCINFO_2(num_parseInt,
224 (2, (static, DOUBLE, ParseInt, CONTEXT, STRING, 1, 1)),
225 (1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, 1)))
226
227 JS_DEFINE_TRCINFO_1(num_parseFloat,
228 (2, (static, DOUBLE, ParseFloat, CONTEXT, STRING, 1, 1)))
229
230 #endif /* JS_TRACER */
231
232 static JSFunctionSpec number_functions[] = {
233 JS_FN(js_isNaN_str, num_isNaN, 1,0),
234 JS_FN(js_isFinite_str, num_isFinite, 1,0),
235 JS_TN(js_parseFloat_str, num_parseFloat, 1,0, num_parseFloat_trcinfo),
236 JS_TN(js_parseInt_str, num_parseInt, 2,0, num_parseInt_trcinfo),
237 JS_FS_END
238 };
239
240 JSClass js_NumberClass = {
241 js_Number_str,
242 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
243 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
244 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
245 JSCLASS_NO_OPTIONAL_MEMBERS
246 };
247
248 static JSBool
249 Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
250 {
251 jsval v;
252 jsdouble d;
253
254 if (argc != 0) {
255 d = js_ValueToNumber(cx, &argv[0]);
256 v = argv[0];
257 if (JSVAL_IS_NULL(v))
258 return JS_FALSE;
259 if (v != JSVAL_TRUE) {
260 JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v));
261 } else {
262 if (!js_NewNumberInRootedValue(cx, d, &argv[0]))
263 return JS_FALSE;
264 v = argv[0];
265 }
266 } else {
267 v = JSVAL_ZERO;
268 }
269 if (!JS_IsConstructing(cx)) {
270 *rval = v;
271 return JS_TRUE;
272 }
273 STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, v);
274 return JS_TRUE;
275 }
276
277 #if JS_HAS_TOSOURCE
278 static JSBool
279 num_toSource(JSContext *cx, uintN argc, jsval *vp)
280 {
281 jsval v;
282 jsdouble d;
283 char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
284 char buf[64];
285 JSString *str;
286
287 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
288 return JS_FALSE;
289 JS_ASSERT(JSVAL_IS_NUMBER(v));
290 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
291 numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
292 if (!numStr) {
293 JS_ReportOutOfMemory(cx);
294 return JS_FALSE;
295 }
296 JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr);
297 str = JS_NewStringCopyZ(cx, buf);
298 if (!str)
299 return JS_FALSE;
300 *vp = STRING_TO_JSVAL(str);
301 return JS_TRUE;
302 }
303 #endif
304
305 /* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
306 static char *
307 IntToCString(jsint i, jsint base, char *buf, size_t bufSize)
308 {
309 char *cp;
310 jsuint u;
311
312 u = (i < 0) ? -i : i;
313
314 cp = buf + bufSize; /* one past last buffer cell */
315 *--cp = '\0'; /* null terminate the string to be */
316
317 /*
318 * Build the string from behind. We use multiply and subtraction
319 * instead of modulus because that's much faster.
320 */
321 switch (base) {
322 case 10:
323 do {
324 jsuint newu = u / 10;
325 *--cp = (char)(u - newu * 10) + '0';
326 u = newu;
327 } while (u != 0);
328 break;
329 case 16:
330 do {
331 jsuint newu = u / 16;
332 *--cp = "0123456789abcdef"[u - newu * 16];
333 u = newu;
334 } while (u != 0);
335 break;
336 default:
337 JS_ASSERT(base >= 2 && base <= 36);
338 do {
339 jsuint newu = u / base;
340 *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base];
341 u = newu;
342 } while (u != 0);
343 break;
344 }
345 if (i < 0)
346 *--cp = '-';
347
348 JS_ASSERT(cp >= buf);
349 return cp;
350 }
351
352 static JSBool
353 num_toString(JSContext *cx, uintN argc, jsval *vp)
354 {
355 jsval v;
356 jsdouble d;
357 jsint base;
358 JSString *str;
359
360 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
361 return JS_FALSE;
362 JS_ASSERT(JSVAL_IS_NUMBER(v));
363 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
364 base = 10;
365 if (argc != 0 && !JSVAL_IS_VOID(vp[2])) {
366 base = js_ValueToECMAInt32(cx, &vp[2]);
367 if (JSVAL_IS_NULL(vp[2]))
368 return JS_FALSE;
369 if (base < 2 || base > 36) {
370 char numBuf[12];
371 char *numStr = IntToCString(base, 10, numBuf, sizeof numBuf);
372 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
373 numStr);
374 return JS_FALSE;
375 }
376 }
377 if (base == 10) {
378 str = js_NumberToString(cx, d);
379 } else {
380 char *dStr = JS_dtobasestr(base, d);
381 if (!dStr) {
382 JS_ReportOutOfMemory(cx);
383 return JS_FALSE;
384 }
385 str = JS_NewStringCopyZ(cx, dStr);
386 free(dStr);
387 }
388 if (!str)
389 return JS_FALSE;
390 *vp = STRING_TO_JSVAL(str);
391 return JS_TRUE;
392 }
393
394 static JSBool
395 num_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
396 {
397 char thousandsLength, decimalLength;
398 const char *numGrouping, *tmpGroup;
399 JSRuntime *rt;
400 JSString *numStr, *str;
401 const char *num, *end, *tmpSrc;
402 char *buf, *tmpDest;
403 const char *nint;
404 int digits, size, remainder, nrepeat;
405
406 /*
407 * Create the string, move back to bytes to make string twiddling
408 * a bit easier and so we can insert platform charset seperators.
409 */
410 if (!num_toString(cx, 0, vp))
411 return JS_FALSE;
412 JS_ASSERT(JSVAL_IS_STRING(*vp));
413 numStr = JSVAL_TO_STRING(*vp);
414 num = js_GetStringBytes(cx, numStr);
415 if (!num)
416 return JS_FALSE;
417
418 /*
419 * Find the first non-integer value, whether it be a letter as in
420 * 'Infinity', a decimal point, or an 'e' from exponential notation.
421 */
422 nint = num;
423 if (*nint == '-')
424 nint++;
425 while (*nint >= '0' && *nint <= '9')
426 nint++;
427 digits = nint - num;
428 end = num + digits;
429 if (!digits)
430 return JS_TRUE;
431
432 rt = cx->runtime;
433 thousandsLength = strlen(rt->thousandsSeparator);
434 decimalLength = strlen(rt->decimalSeparator);
435
436 /* Figure out how long resulting string will be. */
437 size = digits + (*nint ? strlen(nint + 1) + 1 : 0);
438 if (*nint == '.')
439 size += decimalLength;
440
441 numGrouping = tmpGroup = rt->numGrouping;
442 remainder = digits;
443 if (*num == '-')
444 remainder--;
445
446 while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
447 if (*tmpGroup >= remainder)
448 break;
449 size += thousandsLength;
450 remainder -= *tmpGroup;
451 tmpGroup++;
452 }
453 if (*tmpGroup == '\0' && *numGrouping != '\0') {
454 nrepeat = (remainder - 1) / tmpGroup[-1];
455 size += thousandsLength * nrepeat;
456 remainder -= nrepeat * tmpGroup[-1];
457 } else {
458 nrepeat = 0;
459 }
460 tmpGroup--;
461
462 buf = (char *)JS_malloc(cx, size + 1);
463 if (!buf)
464 return JS_FALSE;
465
466 tmpDest = buf;
467 tmpSrc = num;
468
469 while (*tmpSrc == '-' || remainder--)
470 *tmpDest++ = *tmpSrc++;
471 while (tmpSrc < end) {
472 strcpy(tmpDest, rt->thousandsSeparator);
473 tmpDest += thousandsLength;
474 memcpy(tmpDest, tmpSrc, *tmpGroup);
475 tmpDest += *tmpGroup;
476 tmpSrc += *tmpGroup;
477 if (--nrepeat < 0)
478 tmpGroup--;
479 }
480
481 if (*nint == '.') {
482 strcpy(tmpDest, rt->decimalSeparator);
483 tmpDest += decimalLength;
484 strcpy(tmpDest, nint + 1);
485 } else {
486 strcpy(tmpDest, nint);
487 }
488
489 if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
490 return cx->localeCallbacks->localeToUnicode(cx, buf, vp);
491
492 str = JS_NewString(cx, buf, size);
493 if (!str) {
494 JS_free(cx, buf);
495 return JS_FALSE;
496 }
497
498 *vp = STRING_TO_JSVAL(str);
499 return JS_TRUE;
500 }
501
502 static JSBool
503 num_valueOf(JSContext *cx, uintN argc, jsval *vp)
504 {
505 jsval v;
506 JSObject *obj;
507
508 v = vp[1];
509 if (JSVAL_IS_NUMBER(v)) {
510 *vp = v;
511 return JS_TRUE;
512 }
513 obj = JS_THIS_OBJECT(cx, vp);
514 if (!JS_InstanceOf(cx, obj, &js_NumberClass, vp + 2))
515 return JS_FALSE;
516 *vp = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
517 return JS_TRUE;
518 }
519
520
521 #define MAX_PRECISION 100
522
523 static JSBool
524 num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
525 jsint precisionMin, jsint precisionMax, jsint precisionOffset,
526 uintN argc, jsval *vp)
527 {
528 jsval v;
529 jsdouble d, precision;
530 JSString *str;
531
532 /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
533 char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)];
534 char *numStr;
535
536 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
537 return JS_FALSE;
538 JS_ASSERT(JSVAL_IS_NUMBER(v));
539 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
540
541 if (argc == 0) {
542 precision = 0.0;
543 oneArgMode = zeroArgMode;
544 } else {
545 precision = js_ValueToNumber(cx, &vp[2]);
546 if (JSVAL_IS_NULL(vp[2]))
547 return JS_FALSE;
548 precision = js_DoubleToInteger(precision);
549 if (precision < precisionMin || precision > precisionMax) {
550 numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
551 if (!numStr)
552 JS_ReportOutOfMemory(cx);
553 else
554 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
555 return JS_FALSE;
556 }
557 }
558
559 numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
560 if (!numStr) {
561 JS_ReportOutOfMemory(cx);
562 return JS_FALSE;
563 }
564 str = JS_NewStringCopyZ(cx, numStr);
565 if (!str)
566 return JS_FALSE;
567 *vp = STRING_TO_JSVAL(str);
568 return JS_TRUE;
569 }
570
571 /*
572 * In the following three implementations, we allow a larger range of precision
573 * than ECMA requires; this is permitted by ECMA-262.
574 */
575 static JSBool
576 num_toFixed(JSContext *cx, uintN argc, jsval *vp)
577 {
578 return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0,
579 argc, vp);
580 }
581
582 static JSBool
583 num_toExponential(JSContext *cx, uintN argc, jsval *vp)
584 {
585 return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0,
586 MAX_PRECISION, 1, argc, vp);
587 }
588
589 static JSBool
590 num_toPrecision(JSContext *cx, uintN argc, jsval *vp)
591 {
592 if (argc == 0 || JSVAL_IS_VOID(vp[2]))
593 return num_toString(cx, 0, vp);
594 return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
595 argc, vp);
596 }
597
598 #ifdef JS_TRACER
599
600 JS_DEFINE_TRCINFO_2(num_toString,
601 (3, (static, STRING, NumberToStringWithBase, CONTEXT, THIS_DOUBLE, INT32, 1, 1)),
602 (2, (extern, STRING, js_NumberToString, CONTEXT, THIS_DOUBLE, 1, 1)))
603
604 #endif /* JS_TRACER */
605
606 static JSFunctionSpec number_methods[] = {
607 #if JS_HAS_TOSOURCE
608 JS_FN(js_toSource_str, num_toSource, 0,JSFUN_THISP_NUMBER),
609 #endif
610 JS_TN(js_toString_str, num_toString, 1,JSFUN_THISP_NUMBER,
611 num_toString_trcinfo),
612 JS_FN(js_toLocaleString_str, num_toLocaleString, 0,JSFUN_THISP_NUMBER),
613 JS_FN(js_valueOf_str, num_valueOf, 0,JSFUN_THISP_NUMBER),
614 JS_FN(js_toJSON_str, num_valueOf, 0,JSFUN_THISP_NUMBER),
615 JS_FN("toFixed", num_toFixed, 1,JSFUN_THISP_NUMBER),
616 JS_FN("toExponential", num_toExponential, 1,JSFUN_THISP_NUMBER),
617 JS_FN("toPrecision", num_toPrecision, 1,JSFUN_THISP_NUMBER),
618 JS_FS_END
619 };
620
621 /* NB: Keep this in synch with number_constants[]. */
622 enum nc_slot {
623 NC_NaN,
624 NC_POSITIVE_INFINITY,
625 NC_NEGATIVE_INFINITY,
626 NC_MAX_VALUE,
627 NC_MIN_VALUE,
628 NC_LIMIT
629 };
630
631 /*
632 * Some to most C compilers forbid spelling these at compile time, or barf
633 * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
634 * using union jsdpun.
635 */
636 static JSConstDoubleSpec number_constants[] = {
637 {0, js_NaN_str, 0,{0,0,0}},
638 {0, "POSITIVE_INFINITY", 0,{0,0,0}},
639 {0, "NEGATIVE_INFINITY", 0,{0,0,0}},
640 {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
641 {0, "MIN_VALUE", 0,{0,0,0}},
642 {0,0,0,{0,0,0}}
643 };
644
645 jsdouble js_NaN;
646
647 #if (defined XP_WIN || defined XP_OS2) && \
648 !defined WINCE && \
649 !defined __MWERKS__ && \
650 (defined _M_IX86 || \
651 (defined __GNUC__ && !defined __MINGW32__))
652
653 /*
654 * Set the exception mask to mask all exceptions and set the FPU precision
655 * to 53 bit mantissa.
656 * On Alpha platform this is handled via Compiler option.
657 */
658 #define FIX_FPU() _control87(MCW_EM | PC_53, MCW_EM | MCW_PC)
659
660 #else
661
662 #define FIX_FPU() ((void)0)
663
664 #endif
665
666 JSBool
667 js_InitRuntimeNumberState(JSContext *cx)
668 {
669 JSRuntime *rt;
670 jsdpun u;
671 struct lconv *locale;
672
673 rt = cx->runtime;
674 JS_ASSERT(!rt->jsNaN);
675
676 FIX_FPU();
677
678 u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
679 u.s.lo = 0xffffffff;
680 number_constants[NC_NaN].dval = js_NaN = u.d;
681 rt->jsNaN = js_NewWeaklyRootedDouble(cx, js_NaN);
682 if (!rt->jsNaN)
683 return JS_FALSE;
684
685 u.s.hi = JSDOUBLE_HI32_EXPMASK;
686 u.s.lo = 0x00000000;
687 number_constants[NC_POSITIVE_INFINITY].dval = u.d;
688 rt->jsPositiveInfinity = js_NewWeaklyRootedDouble(cx, u.d);
689 if (!rt->jsPositiveInfinity)
690 return JS_FALSE;
691
692 u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
693 u.s.lo = 0x00000000;
694 number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
695 rt->jsNegativeInfinity = js_NewWeaklyRootedDouble(cx, u.d);
696 if (!rt->jsNegativeInfinity)
697 return JS_FALSE;
698
699 u.s.hi = 0;
700 u.s.lo = 1;
701 number_constants[NC_MIN_VALUE].dval = u.d;
702
703 locale = localeconv();
704 rt->thousandsSeparator =
705 JS_strdup(cx, locale->thousands_sep ? locale->thousands_sep : "'");
706 rt->decimalSeparator =
707 JS_strdup(cx, locale->decimal_point ? locale->decimal_point : ".");
708 rt->numGrouping =
709 JS_strdup(cx, locale->grouping ? locale->grouping : "\3\0");
710
711 return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping;
712 }
713
714 void
715 js_TraceRuntimeNumberState(JSTracer *trc)
716 {
717 JSRuntime *rt;
718
719 rt = trc->context->runtime;
720 if (rt->jsNaN)
721 JS_CALL_DOUBLE_TRACER(trc, rt->jsNaN, "NaN");
722 if (rt->jsPositiveInfinity)
723 JS_CALL_DOUBLE_TRACER(trc, rt->jsPositiveInfinity, "+Infinity");
724 if (rt->jsNegativeInfinity)
725 JS_CALL_DOUBLE_TRACER(trc, rt->jsNegativeInfinity, "-Infinity");
726 }
727
728 void
729 js_FinishRuntimeNumberState(JSContext *cx)
730 {
731 JSRuntime *rt = cx->runtime;
732
733 js_UnlockGCThingRT(rt, rt->jsNaN);
734 js_UnlockGCThingRT(rt, rt->jsNegativeInfinity);
735 js_UnlockGCThingRT(rt, rt->jsPositiveInfinity);
736
737 rt->jsNaN = NULL;
738 rt->jsNegativeInfinity = NULL;
739 rt->jsPositiveInfinity = NULL;
740
741 JS_free(cx, (void *)rt->thousandsSeparator);
742 JS_free(cx, (void *)rt->decimalSeparator);
743 JS_free(cx, (void *)rt->numGrouping);
744 rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL;
745 }
746
747 JSObject *
748 js_InitNumberClass(JSContext *cx, JSObject *obj)
749 {
750 JSObject *proto, *ctor;
751 JSRuntime *rt;
752
753 /* XXX must do at least once per new thread, so do it per JSContext... */
754 FIX_FPU();
755
756 if (!JS_DefineFunctions(cx, obj, number_functions))
757 return NULL;
758
759 proto = JS_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1,
760 NULL, number_methods, NULL, NULL);
761 if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
762 return NULL;
763 STOBJ_SET_SLOT(proto, JSSLOT_PRIVATE, JSVAL_ZERO);
764 if (!JS_DefineConstDoubles(cx, ctor, number_constants))
765 return NULL;
766
767 /* ECMA 15.1.1.1 */
768 rt = cx->runtime;
769 if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN),
770 NULL, NULL, JSPROP_PERMANENT)) {
771 return NULL;
772 }
773
774 /* ECMA 15.1.1.2 */
775 if (!JS_DefineProperty(cx, obj, js_Infinity_str,
776 DOUBLE_TO_JSVAL(rt->jsPositiveInfinity),
777 NULL, NULL, JSPROP_PERMANENT)) {
778 return NULL;
779 }
780 return proto;
781 }
782
783 JSBool
784 js_NewNumberInRootedValue(JSContext *cx, jsdouble d, jsval *vp)
785 {
786 jsint i;
787
788 if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
789 *vp = INT_TO_JSVAL(i);
790 return JS_TRUE;
791 }
792 return js_NewDoubleInRootedValue(cx, d, vp);
793 }
794
795 JSBool
796 js_NewWeaklyRootedNumber(JSContext *cx, jsdouble d, jsval *rval)
797 {
798 jsint i;
799 if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
800 *rval = INT_TO_JSVAL(i);
801 return JS_TRUE;
802 }
803 return JS_NewDoubleValue(cx, d, rval);
804 }
805
806 /*
807 * Convert a number to C string. The buf must be large enough to accommodate
808 * the result, including '-' and '\0', if base == 10 or d is an integer that
809 * fits in 32 bits. The caller must free the resulting pointer if it does not
810 * point into buf.
811 */
812 static char *
813 NumberToCString(JSContext *cx, jsdouble d, jsint base, char *buf, size_t bufSize)
814 {
815 jsint i;
816 char *numStr;
817
818 JS_ASSERT(bufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
819 if (JSDOUBLE_IS_INT(d, i)) {
820 numStr = IntToCString(i, base, buf, bufSize);
821 } else {
822 if (base == 10)
823 numStr = JS_dtostr(buf, bufSize, DTOSTR_STANDARD, 0, d);
824 else
825 numStr = JS_dtobasestr(base, d);
826 if (!numStr) {
827 JS_ReportOutOfMemory(cx);
828 return NULL;
829 }
830 }
831 return numStr;
832 }
833
834 static JSString * JS_FASTCALL
835 NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
836 {
837 /*
838 * The longest possible result here that would need to fit in buf is
839 * (-0x80000000).toString(2), which has length 33. (This can produce
840 * longer results, but in those cases buf is not used; see comment at
841 * NumberToCString.)
842 */
843 char buf[34];
844 char *numStr;
845 JSString *s;
846
847 if (base < 2 || base > 36)
848 return NULL;
849 numStr = NumberToCString(cx, d, base, buf, sizeof buf);
850 if (!numStr)
851 return NULL;
852 s = JS_NewStringCopyZ(cx, numStr);
853 if (!(numStr >= buf && numStr < buf + sizeof buf))
854 free(numStr);
855 return s;
856 }
857
858 JSString * JS_FASTCALL
859 js_NumberToString(JSContext *cx, jsdouble d)
860 {
861 return NumberToStringWithBase(cx, d, 10);
862 }
863
864 jsdouble
865 js_ValueToNumber(JSContext *cx, jsval *vp)
866 {
867 jsval v;
868 JSString *str;
869 const jschar *bp, *end, *ep;
870 jsdouble d, *dp;
871 JSObject *obj;
872 JSTempValueRooter tvr;
873
874 v = *vp;
875 for (;;) {
876 if (JSVAL_IS_INT(v))
877 return (jsdouble) JSVAL_TO_INT(v);
878 if (JSVAL_IS_DOUBLE(v))
879 return *JSVAL_TO_DOUBLE(v);
880 if (JSVAL_IS_STRING(v)) {
881 str = JSVAL_TO_STRING(v);
882
883 /*
884 * Note that ECMA doesn't treat a string beginning with a '0' as
885 * an octal number here. This works because all such numbers will
886 * be interpreted as decimal by js_strtod and will never get
887 * passed to js_strtointeger (which would interpret them as
888 * octal).
889 */
890 JSSTRING_CHARS_AND_END(str, bp, end);
891 if ((!js_strtod(cx, bp, end, &ep, &d) ||
892 js_SkipWhiteSpace(ep, end) != end) &&
893 (!js_strtointeger(cx, bp, end, &ep, 0, &d) ||
894 js_SkipWhiteSpace(ep, end) != end)) {
895 break;
896 }
897
898 /*
899 * JSVAL_TRUE indicates that double jsval was never constructed
900 * for the result.
901 */
902 *vp = JSVAL_TRUE;
903 return d;
904 }
905 if (JSVAL_IS_BOOLEAN(v)) {
906 if (JSVAL_TO_BOOLEAN(v)) {
907 *vp = JSVAL_ONE;
908 return 1.0;
909 } else {
910 *vp = JSVAL_ZERO;
911 return 0.0;
912 }
913 }
914 if (JSVAL_IS_NULL(v)) {
915 *vp = JSVAL_ZERO;
916 return 0.0;
917 }
918 if (JSVAL_IS_VOID(v))
919 break;
920
921 JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
922 obj = JSVAL_TO_OBJECT(v);
923
924 /*
925 * vp roots obj so we cannot use it as an extra root for
926 * OBJ_DEFAULT_VALUE result when calling the hook.
927 */
928 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
929 if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &tvr.u.value))
930 obj = NULL;
931 else
932 v = *vp = tvr.u.value;
933 JS_POP_TEMP_ROOT(cx, &tvr);
934 if (!obj) {
935 *vp = JSVAL_NULL;
936 return 0.0;
937 }
938 if (!JSVAL_IS_PRIMITIVE(v))
939 break;
940 }
941
942 dp = cx->runtime->jsNaN;
943 *vp = DOUBLE_TO_JSVAL(dp);
944 return *dp;
945 }
946
947 int32
948 js_ValueToECMAInt32(JSContext *cx, jsval *vp)
949 {
950 jsval v;
951 jsdouble d;
952
953 v = *vp;
954 if (JSVAL_IS_INT(v))
955 return JSVAL_TO_INT(v);
956 if (JSVAL_IS_DOUBLE(v)) {
957 d = *JSVAL_TO_DOUBLE(v);
958 *vp = JSVAL_TRUE;
959 } else {
960 d = js_ValueToNumber(cx, vp);
961 if (JSVAL_IS_NULL(*vp))
962 return 0;
963 *vp = JSVAL_TRUE;
964 }
965 return js_DoubleToECMAInt32(d);
966 }
967
968 int32
969 js_DoubleToECMAInt32(jsdouble d)
970 {
971 int32 i;
972 jsdouble two32, two31;
973
974 if (!JSDOUBLE_IS_FINITE(d))
975 return 0;
976
977 i = (int32) d;
978 if ((jsdouble) i == d)
979 return i;
980
981 two32 = 4294967296.0;
982 two31 = 2147483648.0;
983 d = fmod(d, two32);
984 d = (d >= 0) ? floor(d) : ceil(d) + two32;
985 return (int32) (d >= two31 ? d - two32 : d);
986 }
987
988 uint32
989 js_ValueToECMAUint32(JSContext *cx, jsval *vp)
990 {
991 jsval v;
992 jsint i;
993 jsdouble d;
994
995 v = *vp;
996 if (JSVAL_IS_INT(v)) {
997 i = JSVAL_TO_INT(v);
998 if (i < 0)
999 *vp = JSVAL_TRUE;
1000 return (uint32) i;
1001 }
1002 if (JSVAL_IS_DOUBLE(v)) {
1003 d = *JSVAL_TO_DOUBLE(v);
1004 *vp = JSVAL_TRUE;
1005 } else {
1006 d = js_ValueToNumber(cx, vp);
1007 if (JSVAL_IS_NULL(*vp))
1008 return 0;
1009 *vp = JSVAL_TRUE;
1010 }
1011 return js_DoubleToECMAUint32(d);
1012 }
1013
1014 uint32
1015 js_DoubleToECMAUint32(jsdouble d)
1016 {
1017 int32 i;
1018 JSBool neg;
1019 jsdouble two32;
1020
1021 if (!JSDOUBLE_IS_FINITE(d))
1022 return 0;
1023
1024 /*
1025 * We check whether d fits int32, not uint32, as all but the ">>>" bit
1026 * manipulation bytecode stores the result as int, not uint. When the
1027 * result does not fit int jsval, it will be stored as a negative double.
1028 */
1029 i = (int32) d;
1030 if ((jsdouble) i == d)
1031 return (int32)i;
1032
1033 neg = (d < 0);
1034 d = floor(neg ? -d : d);
1035 d = neg ? -d : d;
1036
1037 two32 = 4294967296.0;
1038 d = fmod(d, two32);
1039
1040 return (uint32) (d >= 0 ? d : d + two32);
1041 }
1042
1043 int32
1044 js_ValueToInt32(JSContext *cx, jsval *vp)
1045 {
1046 jsval v;
1047 jsdouble d;
1048
1049 v = *vp;
1050 if (JSVAL_IS_INT(v))
1051 return JSVAL_TO_INT(v);
1052 d = js_ValueToNumber(cx, vp);
1053 if (JSVAL_IS_NULL(*vp))
1054 return 0;
1055 if (JSVAL_IS_INT(*vp))
1056 return JSVAL_TO_INT(*vp);
1057
1058 *vp = JSVAL_TRUE;
1059 if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
1060 js_ReportValueError(cx, JSMSG_CANT_CONVERT,
1061 JSDVG_SEARCH_STACK, v, NULL);
1062 *vp = JSVAL_NULL;
1063 return 0;
1064 }
1065 return (int32) floor(d + 0.5); /* Round to nearest */
1066 }
1067
1068 uint16
1069 js_ValueToUint16(JSContext *cx, jsval *vp)
1070 {
1071 jsdouble d;
1072 uint16 u;
1073 jsuint m;
1074 JSBool neg;
1075
1076 d = js_ValueToNumber(cx, vp);
1077 if (JSVAL_IS_NULL(*vp))
1078 return 0;
1079
1080 if (JSVAL_IS_INT(*vp)) {
1081 u = (uint16) JSVAL_TO_INT(*vp);
1082 } else if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
1083 u = (uint16) 0;
1084 } else {
1085 u = (uint16) d;
1086 if ((jsdouble) u != d) {
1087 neg = (d < 0);
1088 d = floor(neg ? -d : d);
1089 d = neg ? -d : d;
1090 m = JS_BIT(16);
1091 d = fmod(d, (double) m);
1092 if (d < 0)
1093 d += m;
1094 u = (uint16) d;
1095 }
1096 }
1097 *vp = INT_TO_JSVAL(u);
1098 return u;
1099 }
1100
1101 jsdouble
1102 js_DoubleToInteger(jsdouble d)
1103 {
1104 JSBool neg;
1105
1106 if (d == 0)
1107 return d;
1108 if (!JSDOUBLE_IS_FINITE(d)) {
1109 if (JSDOUBLE_IS_NaN(d))
1110 return 0;
1111 return d;
1112 }
1113 neg = (d < 0);
1114 d = floor(neg ? -d : d);
1115 return neg ? -d : d;
1116 }
1117
1118 JSBool
1119 js_strtod(JSContext *cx, const jschar *s, const jschar *send,
1120 const jschar **ep, jsdouble *dp)
1121 {
1122 const jschar *s1;
1123 size_t length, i;
1124 char cbuf[32];
1125 char *cstr, *istr, *estr;
1126 JSBool negative;
1127 jsdouble d;
1128
1129 s1 = js_SkipWhiteSpace(s, send);
1130 length = send - s1;
1131
1132 /* Use cbuf to avoid malloc */
1133 if (length >= sizeof cbuf) {
1134 cstr = (char *) JS_malloc(cx, length + 1);
1135 if (!cstr)
1136 return JS_FALSE;
1137 } else {
1138 cstr = cbuf;
1139 }
1140
1141 for (i = 0; i != length; i++) {
1142 if (s1[i] >> 8)
1143 break;
1144 cstr[i] = (char)s1[i];
1145 }
1146 cstr[i] = 0;
1147
1148 istr = cstr;
1149 if ((negative = (*istr == '-')) != 0 || *istr == '+')
1150 istr++;
1151 if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
1152 d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
1153 estr = istr + 8;
1154 } else {
1155 int err;
1156 d = JS_strtod(cstr, &estr, &err);
1157 if (d == HUGE_VAL)
1158 d = *cx->runtime->jsPositiveInfinity;
1159 else if (d == -HUGE_VAL)
1160 d = *cx->runtime->jsNegativeInfinity;
1161 #ifdef HPUX
1162 if (d == 0.0 && negative) {
1163 /*
1164 * "-0", "-1e-2000" come out as positive zero
1165 * here on HPUX. Force a negative zero instead.
1166 */
1167 JSDOUBLE_HI32(d) = JSDOUBLE_HI32_SIGNBIT;
1168 JSDOUBLE_LO32(d) = 0;
1169 }
1170 #endif
1171 }
1172
1173 i = estr - cstr;
1174 if (cstr != cbuf)
1175 JS_free(cx, cstr);
1176 *ep = i ? s1 + i : s;
1177 *dp = d;
1178 return JS_TRUE;
1179 }
1180
1181 struct BinaryDigitReader
1182 {
1183 uintN base; /* Base of number; must be a power of 2 */
1184 uintN digit; /* Current digit value in radix given by base */
1185 uintN digitMask; /* Mask to extract the next bit from digit */
1186 const jschar *digits; /* Pointer to the remaining digits */
1187 const jschar *end; /* Pointer to first non-digit */
1188 };
1189
1190 /* Return the next binary digit from the number or -1 if done */
1191 static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr)
1192 {
1193 intN bit;
1194
1195 if (bdr->digitMask == 0) {
1196 uintN c;
1197
1198 if (bdr->digits == bdr->end)
1199 return -1;
1200
1201 c = *bdr->digits++;
1202 if ('0' <= c && c <= '9')
1203 bdr->digit = c - '0';
1204 else if ('a' <= c && c <= 'z')
1205 bdr->digit = c - 'a' + 10;
1206 else bdr->digit = c - 'A' + 10;
1207 bdr->digitMask = bdr->base >> 1;
1208 }
1209 bit = (bdr->digit & bdr->digitMask) != 0;
1210 bdr->digitMask >>= 1;
1211 return bit;
1212 }
1213
1214 JSBool
1215 js_strtointeger(JSContext *cx, const jschar *s, const jschar *send,
1216 const jschar **ep, jsint base, jsdouble *dp)
1217 {
1218 const jschar *s1, *start;
1219 JSBool negative;
1220 jsdouble value;
1221
1222 s1 = js_SkipWhiteSpace(s, send);
1223 if (s1 == send)
1224 goto no_digits;
1225 if ((negative = (*s1 == '-')) != 0 || *s1 == '+') {
1226 s1++;
1227 if (s1 == send)
1228 goto no_digits;
1229 }
1230
1231 if (base == 0) {
1232 /* No base supplied, or some base that evaluated to 0. */
1233 if (*s1 == '0') {
1234 /* It's either hex or octal; only increment char if str isn't '0' */
1235 if (s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) {
1236 base = 16;
1237 s1 += 2;
1238 if (s1 == send)
1239 goto no_digits;
1240 } else {
1241 base = 8;
1242 }
1243 } else {
1244 base = 10; /* Default to decimal. */
1245 }
1246 } else if (base == 16) {
1247 /* If base is 16, ignore hex prefix. */
1248 if (*s1 == '0' && s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) {
1249 s1 += 2;
1250 if (s1 == send)
1251 goto no_digits;
1252 }
1253 }
1254
1255 /*
1256 * Done with the preliminaries; find some prefix of the string that's
1257 * a number in the given base.
1258 */
1259 JS_ASSERT(s1 < send);
1260 start = s1;
1261 value = 0.0;
1262 do {
1263 uintN digit;
1264 jschar c = *s1;
1265 if ('0' <= c && c <= '9')
1266 digit = c - '0';
1267 else if ('a' <= c && c <= 'z')
1268 digit = c - 'a' + 10;
1269 else if ('A' <= c && c <= 'Z')
1270 digit = c - 'A' + 10;
1271 else
1272 break;
1273 if (digit >= (uintN)base)
1274 break;
1275 value = value * base + digit;
1276 } while (++s1 != send);
1277
1278 if (value >= 9007199254740992.0) {
1279 if (base == 10) {
1280 /*
1281 * If we're accumulating a decimal number and the number is >=
1282 * 2^53, then the result from the repeated multiply-add above may
1283 * be inaccurate. Call JS_strtod to get the correct answer.
1284 */
1285 size_t i;
1286 size_t length = s1 - start;
1287 char *cstr = (char *) JS_malloc(cx, length + 1);
1288 char *estr;
1289 int err=0;
1290
1291 if (!cstr)
1292 return JS_FALSE;
1293 for (i = 0; i != length; i++)
1294 cstr[i] = (char)start[i];
1295 cstr[length] = 0;
1296
1297 value = JS_strtod(cstr, &estr, &err);
1298 if (err == JS_DTOA_ENOMEM) {
1299 JS_ReportOutOfMemory(cx);
1300 JS_free(cx, cstr);
1301 return JS_FALSE;
1302 }
1303 if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
1304 value = *cx->runtime->jsPositiveInfinity;
1305 JS_free(cx, cstr);
1306 } else if ((base & (base - 1)) == 0) {
1307 /*
1308 * The number may also be inaccurate for power-of-two bases. This
1309 * happens if the addition in value * base + digit causes a round-
1310 * down to an even least significant mantissa bit when the first
1311 * dropped bit is a one. If any of the following digits in the
1312 * number (which haven't been added in yet) are nonzero, then the
1313 * correct action would have been to round up instead of down. An
1314 * example occurs when reading the number 0x1000000000000081, which
1315 * rounds to 0x1000000000000000 instead of 0x1000000000000100.
1316 */
1317 struct BinaryDigitReader bdr;
1318 intN bit, bit2;
1319 intN j;
1320
1321 bdr.base = base;
1322 bdr.digitMask = 0;
1323 bdr.digits = start;
1324 bdr.end = s1;
1325 value = 0.0;
1326
1327 /* Skip leading zeros. */
1328 do {
1329 bit = GetNextBinaryDigit(&bdr);
1330 } while (bit == 0);
1331
1332 if (bit == 1) {
1333 /* Gather the 53 significant bits (including the leading 1) */
1334 value = 1.0;
1335 for (j = 52; j; j--) {
1336 bit = GetNextBinaryDigit(&bdr);
1337 if (bit < 0)
1338 goto done;
1339 value = value*2 + bit;
1340 }
1341 /* bit2 is the 54th bit (the first dropped from the mantissa) */
1342 bit2 = GetNextBinaryDigit(&bdr);
1343 if (bit2 >= 0) {
1344 jsdouble factor = 2.0;
1345 intN sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
1346 intN bit3;
1347
1348 while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) {
1349 sticky |= bit3;
1350 factor *= 2;
1351 }
1352 value += bit2 & (bit | sticky);
1353 value *= factor;
1354 }
1355 done:;
1356 }
1357 }
1358 }
1359 /* We don't worry about inaccurate numbers for any other base. */
1360
1361 if (s1 == start) {
1362 no_digits:
1363 *dp = 0.0;
1364 *ep = s;
1365 } else {
1366 *dp = negative ? -value : value;
1367 *ep = s1;
1368 }
1369 return JS_TRUE;
1370 }

  ViewVC Help
Powered by ViewVC 1.1.24