40 |
#ifndef jsnum_h___ |
#ifndef jsnum_h___ |
41 |
#define jsnum_h___ |
#define jsnum_h___ |
42 |
|
|
43 |
|
#include <math.h> |
44 |
|
#if defined(XP_WIN) || defined(XP_OS2) |
45 |
|
#include <float.h> |
46 |
|
#endif |
47 |
|
#ifdef SOLARIS |
48 |
|
#include <ieeefp.h> |
49 |
|
#endif |
50 |
|
|
51 |
/* |
/* |
52 |
* JS number (IEEE double) interface. |
* JS number (IEEE double) interface. |
53 |
* |
* |
82 |
jsdouble d; |
jsdouble d; |
83 |
} jsdpun; |
} jsdpun; |
84 |
|
|
85 |
#if (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || __GNUC__ > 2 |
static inline int |
86 |
/* |
JSDOUBLE_IS_NaN(jsdouble d) |
87 |
* This version of the macros is safe for the alias optimizations that gcc |
{ |
88 |
* does, but uses gcc-specific extensions. |
#ifdef WIN32 |
89 |
*/ |
return _isnan(d); |
90 |
|
#else |
91 |
#define JSDOUBLE_HI32(x) (__extension__ ({ jsdpun u; u.d = (x); u.s.hi; })) |
return isnan(d); |
92 |
#define JSDOUBLE_LO32(x) (__extension__ ({ jsdpun u; u.d = (x); u.s.lo; })) |
#endif |
93 |
#define JSDOUBLE_SET_HI32(x, y) \ |
} |
|
(__extension__ ({ jsdpun u; u.d = (x); u.s.hi = (y); (x) = u.d; })) |
|
|
#define JSDOUBLE_SET_LO32(x, y) \ |
|
|
(__extension__ ({ jsdpun u; u.d = (x); u.s.lo = (y); (x) = u.d; })) |
|
|
|
|
|
#else /* not or old GNUC */ |
|
|
|
|
|
/* |
|
|
* We don't know of any non-gcc compilers that perform alias optimization, |
|
|
* so this code should work. |
|
|
*/ |
|
94 |
|
|
95 |
#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA) |
static inline int |
96 |
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1]) |
JSDOUBLE_IS_FINITE(jsdouble d) |
97 |
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0]) |
{ |
98 |
|
#ifdef WIN32 |
99 |
|
return _finite(d); |
100 |
#else |
#else |
101 |
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0]) |
return finite(d); |
|
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1]) |
|
102 |
#endif |
#endif |
103 |
|
} |
104 |
|
|
105 |
#define JSDOUBLE_SET_HI32(x, y) (JSDOUBLE_HI32(x)=(y)) |
static inline int |
106 |
#define JSDOUBLE_SET_LO32(x, y) (JSDOUBLE_LO32(x)=(y)) |
JSDOUBLE_IS_INFINITE(jsdouble d) |
107 |
|
{ |
108 |
|
#ifdef WIN32 |
109 |
|
int c = _fpclass(d); |
110 |
|
return c == _FPCLASS_NINF || c == _FPCLASS_PINF; |
111 |
|
#elif defined(SOLARIS) |
112 |
|
return !finite(d) && !isnan(d); |
113 |
|
#else |
114 |
|
return isinf(d); |
115 |
|
#endif |
116 |
|
} |
117 |
|
|
118 |
#endif /* not or old GNUC */ |
static inline int |
119 |
|
JSDOUBLE_IS_NEGZERO(jsdouble d) |
120 |
|
{ |
121 |
|
#ifdef WIN32 |
122 |
|
return (d == 0 && (_fpclass(d) & _FPCLASS_NZ)); |
123 |
|
#elif defined(SOLARIS) |
124 |
|
return (d == 0 && copysign(1, d) < 0); |
125 |
|
#else |
126 |
|
return (d == 0 && signbit(d)); |
127 |
|
#endif |
128 |
|
} |
129 |
|
|
130 |
#define JSDOUBLE_HI32_SIGNBIT 0x80000000 |
#define JSDOUBLE_HI32_SIGNBIT 0x80000000 |
131 |
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000 |
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000 |
132 |
#define JSDOUBLE_HI32_MANTMASK 0x000fffff |
#define JSDOUBLE_HI32_MANTMASK 0x000fffff |
133 |
|
|
134 |
#define JSDOUBLE_IS_NaN(x) \ |
static inline int |
135 |
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \ |
JSDOUBLE_IS_INT(jsdouble d, jsint& i) |
136 |
(JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK))) |
{ |
137 |
|
if (JSDOUBLE_IS_NEGZERO(d)) |
138 |
#define JSDOUBLE_IS_INFINITE(x) \ |
return false; |
139 |
((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \ |
return d == (i = jsint(d)); |
140 |
!JSDOUBLE_LO32(x)) |
} |
141 |
|
|
142 |
#define JSDOUBLE_IS_FINITE(x) \ |
static inline int |
143 |
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK) |
JSDOUBLE_IS_NEG(jsdouble d) |
144 |
|
{ |
145 |
#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \ |
#ifdef WIN32 |
146 |
JSDOUBLE_LO32(d) == 0) |
return JSDOUBLE_IS_NEGZERO(d) || d < 0; |
147 |
|
#elif defined(SOLARIS) |
148 |
|
return copysign(1, d) < 0; |
149 |
|
#else |
150 |
|
return signbit(d); |
151 |
|
#endif |
152 |
|
} |
153 |
|
|
154 |
/* |
static inline uint32 |
155 |
* JSDOUBLE_IS_INT first checks that d is neither NaN nor infinite, to avoid |
JS_HASH_DOUBLE(jsdouble d) |
156 |
* raising SIGFPE on platforms such as Alpha Linux, then (only if the cast is |
{ |
157 |
* safe) leaves i as (jsint)d. This also avoid anomalous NaN floating point |
jsdpun u; |
158 |
* comparisons under MSVC. |
u.d = d; |
159 |
*/ |
return u.s.lo ^ u.s.hi; |
160 |
#define JSDOUBLE_IS_INT(d, i) (JSDOUBLE_IS_FINITE(d) \ |
} |
|
&& !JSDOUBLE_IS_NEGZERO(d) \ |
|
|
&& ((d) == (i = (jsint)(d)))) |
|
161 |
|
|
162 |
#if defined(XP_WIN) |
#if defined(XP_WIN) |
163 |
#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) \ |
#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) \ |
214 |
js_NumberToString(JSContext *cx, jsdouble d); |
js_NumberToString(JSContext *cx, jsdouble d); |
215 |
|
|
216 |
/* |
/* |
217 |
|
* Convert an integer or double (contained in the given jsval) to a string and |
218 |
|
* append to the given buffer. |
219 |
|
*/ |
220 |
|
extern JSBool JS_FASTCALL |
221 |
|
js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb); |
222 |
|
|
223 |
|
/* |
224 |
* Convert a value to a number. On exit JSVAL_IS_NULL(*vp) iff there was an |
* Convert a value to a number. On exit JSVAL_IS_NULL(*vp) iff there was an |
225 |
* error. If on exit JSVAL_IS_NUMBER(*vp), then *vp holds the jsval that |
* error. If on exit JSVAL_IS_NUMBER(*vp), then *vp holds the jsval that |
226 |
* matches the result. Otherwise *vp is JSVAL_TRUE indicating that the jsval |
* matches the result. Otherwise *vp is JSVAL_TRUE indicating that the jsval |
247 |
/* |
/* |
248 |
* Specialized ToInt32 and ToUint32 converters for doubles. |
* Specialized ToInt32 and ToUint32 converters for doubles. |
249 |
*/ |
*/ |
250 |
extern int32 |
/* |
251 |
js_DoubleToECMAInt32(jsdouble d); |
* From the ES3 spec, 9.5 |
252 |
|
* 2. If Result(1) is NaN, +0, -0, +Inf, or -Inf, return +0. |
253 |
|
* 3. Compute sign(Result(1)) * floor(abs(Result(1))). |
254 |
|
* 4. Compute Result(3) modulo 2^32; that is, a finite integer value k of Number |
255 |
|
* type with positive sign and less than 2^32 in magnitude such the mathematical |
256 |
|
* difference of Result(3) and k is mathematically an integer multiple of 2^32. |
257 |
|
* 5. If Result(4) is greater than or equal to 2^31, return Result(4)- 2^32, |
258 |
|
* otherwise return Result(4). |
259 |
|
*/ |
260 |
|
static inline int32 |
261 |
|
js_DoubleToECMAInt32(jsdouble d) |
262 |
|
{ |
263 |
|
#ifdef __i386__ |
264 |
|
jsdpun du, duh, two32; |
265 |
|
uint32 di_h, u_tmp, expon, shift_amount; |
266 |
|
int32 mask32; |
267 |
|
|
268 |
|
/* |
269 |
|
* Algorithm Outline |
270 |
|
* Step 1. If d is NaN, +/-Inf or |d|>=2^84 or |d|<1, then return 0 |
271 |
|
* All of this is implemented based on an exponent comparison. |
272 |
|
* Step 2. If |d|<2^31, then return (int)d |
273 |
|
* The cast to integer (conversion in RZ mode) returns the correct result. |
274 |
|
* Step 3. If |d|>=2^32, d:=fmod(d, 2^32) is taken -- but without a call |
275 |
|
* Step 4. If |d|>=2^31, then the fractional bits are cleared before |
276 |
|
* applying the correction by 2^32: d - sign(d)*2^32 |
277 |
|
* Step 5. Return (int)d |
278 |
|
*/ |
279 |
|
|
280 |
|
du.d = d; |
281 |
|
di_h = du.s.hi; |
282 |
|
|
283 |
|
u_tmp = (di_h & 0x7ff00000) - 0x3ff00000; |
284 |
|
if (u_tmp >= (0x45300000-0x3ff00000)) { |
285 |
|
// d is Nan, +/-Inf or +/-0, or |d|>=2^(32+52) or |d|<1, in which case result=0 |
286 |
|
return 0; |
287 |
|
} |
288 |
|
|
289 |
|
if (u_tmp < 0x01f00000) { |
290 |
|
// |d|<2^31 |
291 |
|
return int32_t(d); |
292 |
|
} |
293 |
|
|
294 |
|
if (u_tmp > 0x01f00000) { |
295 |
|
// |d|>=2^32 |
296 |
|
expon = u_tmp >> 20; |
297 |
|
shift_amount = expon - 21; |
298 |
|
duh.u64 = du.u64; |
299 |
|
mask32 = 0x80000000; |
300 |
|
if (shift_amount < 32) { |
301 |
|
mask32 >>= shift_amount; |
302 |
|
duh.s.hi = du.s.hi & mask32; |
303 |
|
duh.s.lo = 0; |
304 |
|
} else { |
305 |
|
mask32 >>= (shift_amount-32); |
306 |
|
duh.s.hi = du.s.hi; |
307 |
|
duh.s.lo = du.s.lo & mask32; |
308 |
|
} |
309 |
|
du.d -= duh.d; |
310 |
|
} |
311 |
|
|
312 |
|
di_h = du.s.hi; |
313 |
|
|
314 |
|
// eliminate fractional bits |
315 |
|
u_tmp = (di_h & 0x7ff00000); |
316 |
|
if (u_tmp >= 0x41e00000) { |
317 |
|
// |d|>=2^31 |
318 |
|
expon = u_tmp >> 20; |
319 |
|
shift_amount = expon - (0x3ff - 11); |
320 |
|
mask32 = 0x80000000; |
321 |
|
if (shift_amount < 32) { |
322 |
|
mask32 >>= shift_amount; |
323 |
|
du.s.hi &= mask32; |
324 |
|
du.s.lo = 0; |
325 |
|
} else { |
326 |
|
mask32 >>= (shift_amount-32); |
327 |
|
du.s.lo &= mask32; |
328 |
|
} |
329 |
|
two32.s.hi = 0x41f00000 ^ (du.s.hi & 0x80000000); |
330 |
|
two32.s.lo = 0; |
331 |
|
du.d -= two32.d; |
332 |
|
} |
333 |
|
|
334 |
|
return int32(du.d); |
335 |
|
#else |
336 |
|
int32 i; |
337 |
|
jsdouble two32, two31; |
338 |
|
|
339 |
|
if (!JSDOUBLE_IS_FINITE(d)) |
340 |
|
return 0; |
341 |
|
|
342 |
|
i = (int32) d; |
343 |
|
if ((jsdouble) i == d) |
344 |
|
return i; |
345 |
|
|
346 |
|
two32 = 4294967296.0; |
347 |
|
two31 = 2147483648.0; |
348 |
|
d = fmod(d, two32); |
349 |
|
d = (d >= 0) ? floor(d) : ceil(d) + two32; |
350 |
|
return (int32) (d >= two31 ? d - two32 : d); |
351 |
|
#endif |
352 |
|
} |
353 |
|
|
354 |
extern uint32 |
extern uint32 |
355 |
js_DoubleToECMAUint32(jsdouble d); |
js_DoubleToECMAUint32(jsdouble d); |
377 |
* Convert a jsdouble to an integral number, stored in a jsdouble. |
* Convert a jsdouble to an integral number, stored in a jsdouble. |
378 |
* If d is NaN, return 0. If d is an infinity, return it without conversion. |
* If d is NaN, return 0. If d is an infinity, return it without conversion. |
379 |
*/ |
*/ |
380 |
extern jsdouble |
static inline jsdouble |
381 |
js_DoubleToInteger(jsdouble d); |
js_DoubleToInteger(jsdouble d) |
382 |
|
{ |
383 |
|
if (d == 0) |
384 |
|
return d; |
385 |
|
|
386 |
|
if (!JSDOUBLE_IS_FINITE(d)) { |
387 |
|
if (JSDOUBLE_IS_NaN(d)) |
388 |
|
return 0; |
389 |
|
return d; |
390 |
|
} |
391 |
|
|
392 |
|
JSBool neg = (d < 0); |
393 |
|
d = floor(neg ? -d : d); |
394 |
|
|
395 |
|
return neg ? -d : d; |
396 |
|
} |
397 |
|
|
398 |
/* |
/* |
399 |
* Similar to strtod except that it replaces overflows with infinities of the |
* Similar to strtod except that it replaces overflows with infinities of the |