jsnum.c revision 6b15695578f07a3f72c4c9475c1a261a3021472a
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* IBM Corp.
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* JS number type and wrapper class.
*/
#include "jsstddef.h"
#include <float.h>
#endif
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "jstypes.h"
#include "jsutil.h" /* Added by JSIFY */
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
#include "jsconfig.h"
#include "jsdtoa.h"
#include "jsgc.h"
#include "jsinterp.h"
#include "jsnum.h"
#include "jsobj.h"
#include "jsopcode.h"
#include "jsprf.h"
#include "jsstr.h"
static JSBool
{
jsdouble x;
return JS_FALSE;
return JS_TRUE;
}
static JSBool
{
jsdouble x;
return JS_FALSE;
return JS_TRUE;
}
static JSBool
{
jsdouble d;
if (!str)
return JS_FALSE;
/* XXXbe js_strtod shouldn't require NUL termination */
if (!bp)
return JS_FALSE;
return JS_FALSE;
return JS_TRUE;
}
}
/* See ECMA 15.1.2.2. */
static JSBool
{
jsdouble d;
if (!str)
return JS_FALSE;
if (argc > 1) {
return JS_FALSE;
} else
radix = 0;
return JS_TRUE;
}
/* XXXbe js_strtointeger shouldn't require NUL termination */
if (!bp)
return JS_FALSE;
return JS_FALSE;
return JS_TRUE;
}
}
const char js_Infinity_str[] = "Infinity";
const char js_NaN_str[] = "NaN";
const char js_isNaN_str[] = "isNaN";
const char js_isFinite_str[] = "isFinite";
const char js_parseFloat_str[] = "parseFloat";
const char js_parseInt_str[] = "parseInt";
static JSFunctionSpec number_functions[] = {
{0,0,0,0,0}
};
static JSClass number_class = {
"Number",
};
static JSBool
{
jsdouble d;
jsval v;
if (argc != 0) {
return JS_FALSE;
} else {
d = 0.0;
}
if (!js_NewNumberValue(cx, d, &v))
return JS_FALSE;
*rval = v;
return JS_TRUE;
}
return JS_TRUE;
}
#if JS_HAS_TOSOURCE
static JSBool
{
jsval v;
jsdouble d;
char buf[64];
return JS_FALSE;
JS_ASSERT(JSVAL_IS_NUMBER(v));
if (!numStr) {
return JS_FALSE;
}
if (!str)
return JS_FALSE;
return JS_TRUE;
}
#endif
/* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
static char *
{
char *cp;
jsuint u;
u = (i < 0) ? -i : i;
/*
* Build the string from behind. We use multiply and subtraction
* instead of modulus because that's much faster.
*/
do {
u = newu;
} while (u != 0);
if (i < 0)
*--cp = '-';
return cp;
}
static JSBool
{
jsval v;
jsdouble d;
return JS_FALSE;
JS_ASSERT(JSVAL_IS_NUMBER(v));
base = 10;
if (argc != 0) {
return JS_FALSE;
char numBuf[12];
numStr);
return JS_FALSE;
}
}
if (base == 10)
else {
if (!dStr) {
return JS_FALSE;
}
}
if (!str)
return JS_FALSE;
return JS_TRUE;
}
static JSBool
{
/*
* For now, forcibly ignore the first (or any) argument and return toString().
* ECMA allows this, although it doesn't 'encourage it'.
* [The first argument is being reserved by ECMA and we don't want it confused
* with a radix]
*/
}
static JSBool
{
return JS_FALSE;
return JS_TRUE;
}
#define MAX_PRECISION 100
static JSBool
num_to(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, JSDToStrMode zeroArgMode,
{
jsval v;
char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)], *numStr; /* Use MAX_PRECISION+1 because precisionOffset can be 1 */
return JS_FALSE;
JS_ASSERT(JSVAL_IS_NUMBER(v));
if (JSVAL_IS_VOID(argv[0])) {
precision = 0.0;
} else {
return JS_FALSE;
if (!numStr)
else
return JS_FALSE;
}
}
if (!numStr) {
return JS_FALSE;
}
if (!str)
return JS_FALSE;
return JS_TRUE;
}
static JSBool
{
/* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
}
static JSBool
{
/* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1);
}
static JSBool
{
/* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
}
#endif /* JS_HAS_NUMBER_FORMATS */
static JSFunctionSpec number_methods[] = {
#if JS_HAS_TOSOURCE
{js_toSource_str, num_toSource, 0,0,0},
#endif
{js_toString_str, num_toString, 0,0,0},
{js_toLocaleString_str, num_toLocaleString, 0,0,0},
{js_valueOf_str, num_valueOf, 0,0,0},
#endif
{0,0,0,0,0}
};
/* NB: Keep this in synch with number_constants[]. */
enum nc_slot {
};
/*
* Some to most C compilers forbid spelling these at compile time, or barf
* if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
* using union jsdpun.
*/
static JSConstDoubleSpec number_constants[] = {
{0, js_NaN_str, 0,{0,0,0}},
{0, "POSITIVE_INFINITY", 0,{0,0,0}},
{0, "NEGATIVE_INFINITY", 0,{0,0,0}},
{1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
{0, "MIN_VALUE", 0,{0,0,0}},
{0,0,0,{0,0,0}}
};
#if defined XP_WIN && \
!defined __MWERKS__ && \
(defined _M_IX86 || \
(defined __GNUC__ && !defined __MINGW32__))
/*
* Set the exception mask to mask all exceptions and set the FPU precision
* to 53 bit mantissa.
* On Alpha platform this is handled via Compiler option.
*/
#else
#define FIX_FPU() ((void)0)
#endif
{
jsdpun u;
FIX_FPU();
u.s.lo = 0xffffffff;
return JS_FALSE;
u.s.hi = JSDOUBLE_HI32_EXPMASK;
u.s.lo = 0x00000000;
if (!rt->jsPositiveInfinity ||
return JS_FALSE;
}
u.s.lo = 0x00000000;
if (!rt->jsNegativeInfinity ||
return JS_FALSE;
}
u.s.hi = 0;
u.s.lo = 1;
return JS_TRUE;
}
void
{
}
JSObject *
{
/* XXX must do at least once per new thread, so do it per JSContext... */
FIX_FPU();
return NULL;
return NULL;
return NULL;
/* ECMA 15.1.1.1 */
return NULL;
}
/* ECMA 15.1.1.2 */
return NULL;
}
return proto;
}
jsdouble *
{
if (!dp)
return NULL;
*dp = d;
return dp;
}
void
{
}
{
if (!dp)
return JS_FALSE;
return JS_TRUE;
}
{
jsint i;
SET_FPU();
if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
*rval = INT_TO_JSVAL(i);
} else {
}
RESTORE_FPU();
return ok;
}
JSObject *
{
jsval v;
if (!obj)
return NULL;
if (!js_NewNumberValue(cx, d, &v)) {
return NULL;
}
return obj;
}
JSString *
{
jsint i;
char buf[DTOSTR_STANDARD_BUFFER_SIZE];
char *numStr;
if (JSDOUBLE_IS_INT(d, i))
else {
if (!numStr) {
return NULL;
}
}
}
{
if (JSVAL_IS_OBJECT(v)) {
obj = JSVAL_TO_OBJECT(v);
if (!obj) {
*dp = 0;
return JS_TRUE;
}
return JS_FALSE;
}
if (JSVAL_IS_INT(v)) {
} else if (JSVAL_IS_DOUBLE(v)) {
*dp = *JSVAL_TO_DOUBLE(v);
} else if (JSVAL_IS_STRING(v)) {
str = JSVAL_TO_STRING(v);
/*
* Note that ECMA doesn't treat a string beginning with a '0' as an
* octal number here. This works because all such numbers will be
* interpreted as decimal by js_strtod and will never get passed to
* js_strtointeger (which would interpret them as octal).
*/
/* XXXbe js_strtod shouldn't require NUL termination */
if (!bp)
return JS_FALSE;
goto badstr;
}
} else if (JSVAL_IS_BOOLEAN(v)) {
} else {
if (str) {
}
return JS_FALSE;
#else
#endif
}
return JS_TRUE;
}
{
jsdouble d;
if (!js_ValueToNumber(cx, v, &d))
return JS_FALSE;
}
{
if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
*ip = 0;
return JS_TRUE;
}
if (d >= two31)
else
return JS_TRUE;
}
{
jsdouble d;
if (!js_ValueToNumber(cx, v, &d))
return JS_FALSE;
}
{
if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
*ip = 0;
return JS_TRUE;
}
neg = (d < 0);
d = neg ? -d : d;
d = (d >= 0) ? d : d + two32;
return JS_TRUE;
}
{
jsdouble d;
if (JSVAL_IS_INT(v)) {
*ip = JSVAL_TO_INT(v);
return JS_TRUE;
}
if (!js_ValueToNumber(cx, v, &d))
return JS_FALSE;
if (str) {
}
return JS_FALSE;
}
return JS_TRUE;
}
{
jsdouble d;
jsuint i, m;
if (!js_ValueToNumber(cx, v, &d))
return JS_FALSE;
if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
*ip = 0;
return JS_TRUE;
}
i = (jsuint)d;
if ((jsdouble)i == d) {
return JS_TRUE;
}
neg = (d < 0);
d = neg ? -d : d;
m = JS_BIT(16);
d = fmod(d, (double)m);
if (d < 0)
d += m;
return JS_TRUE;
}
{
if (d == 0)
return d;
if (!JSDOUBLE_IS_FINITE(d)) {
if (JSDOUBLE_IS_NaN(d))
return 0;
return d;
}
neg = (d < 0);
return neg ? -d : d;
}
{
char cbuf[32];
size_t i;
jsdouble d;
/* Use cbuf to avoid malloc */
if (!cstr)
return JS_FALSE;
} else {
}
for (i = 0; i <= length; i++) {
if (s1[i] >> 8) {
cstr[i] = 0;
break;
}
}
istr++;
} else {
int err;
if (err == JS_DTOA_ENOMEM) {
return JS_FALSE;
}
if (err == JS_DTOA_ERANGE) {
if (d == HUGE_VAL)
else if (d == -HUGE_VAL)
}
#ifdef HPUX
if (d == 0.0 && negative) {
/*
* "-0", "-1e-2000" come out as positive zero
* here on HPUX. Force a negative zero instead.
*/
JSDOUBLE_LO32(d) = 0;
}
#endif
}
*dp = d;
return JS_TRUE;
}
struct BinaryDigitReader
{
};
/* Return the next binary digit from the number or -1 if done */
{
uintN c;
return -1;
if ('0' <= c && c <= '9')
else if ('a' <= c && c <= 'z')
}
return bit;
}
{
s1++;
if (base == 0) {
/* No base supplied, or some base that evaluated to 0. */
if (*s1 == '0') {
/* It's either hex or octal; only increment char if str isn't '0' */
s1 += 2;
base = 16;
} else { /* Octal */
base = 8;
}
} else {
}
/* If base is 16, ignore hex prefix. */
s1 += 2;
}
/*
* Done with the preliminaries; find some prefix of the string that's
* a number in the given base.
*/
value = 0.0;
for (;;) {
if ('0' <= c && c <= '9')
digit = c - '0';
else if ('a' <= c && c <= 'z')
else if ('A' <= c && c <= 'Z')
else
break;
break;
s1++;
}
if (value >= 9007199254740992.0) {
if (base == 10) {
/*
* If we're accumulating a decimal number and the number is >=
* 2^53, then the result from the repeated multiply-add above may
* be inaccurate. Call JS_strtod to get the correct answer.
*/
size_t i;
char *estr;
int err=0;
if (!cstr)
return JS_FALSE;
for (i = 0; i != length; i++)
if (err == JS_DTOA_ENOMEM) {
return JS_FALSE;
}
/*
* The number may also be inaccurate for power-of-two bases. This
* happens if the addition in value * base + digit causes a round-
* down to an even least significant mantissa bit when the first
* dropped bit is a one. If any of the following digits in the
* number (which haven't been added in yet) are nonzero, then the
* correct action would have been to round up instead of down. An
* example occurs when reading the number 0x1000000000000081, which
* rounds to 0x1000000000000000 instead of 0x1000000000000100.
*/
struct BinaryDigitReader bdr;
intN j;
value = 0.0;
/* Skip leading zeros. */
do {
} while (bit == 0);
if (bit == 1) {
/* Gather the 53 significant bits (including the leading 1) */
value = 1.0;
for (j = 52; j; j--) {
if (bit < 0)
goto done;
}
/* bit2 is the 54th bit (the first dropped from the mantissa) */
if (bit2 >= 0) {
factor *= 2;
}
}
done:;
}
}
}
/* We don't worry about inaccurate numbers for any other base. */
*dp = 0.0;
*ep = s;
} else {
}
return JS_TRUE;
}