2013-04-16 13:47:10 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
2012-05-21 04:12:37 -07:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* JS math package.
|
|
|
|
*/
|
2012-01-23 03:43:16 -08:00
|
|
|
|
2013-04-18 23:07:18 -07:00
|
|
|
#if defined(XP_WIN)
|
|
|
|
/* _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s(). */
|
|
|
|
#define _CRT_RAND_S
|
|
|
|
#endif
|
|
|
|
|
2013-04-23 23:44:36 -07:00
|
|
|
#include "jsmath.h"
|
|
|
|
|
2012-08-06 13:32:11 -07:00
|
|
|
#include "mozilla/Constants.h"
|
2012-01-23 03:43:16 -08:00
|
|
|
#include "mozilla/FloatingPoint.h"
|
2013-02-15 19:55:36 -08:00
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2013-06-23 04:21:01 -07:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2012-01-23 03:43:16 -08:00
|
|
|
|
2013-07-15 08:03:14 -07:00
|
|
|
#include <algorithm> // for std::max
|
2013-04-18 23:07:18 -07:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
2013-05-31 12:46:33 -07:00
|
|
|
#ifdef XP_UNIX
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "jsapi.h"
|
|
|
|
#include "jsatom.h"
|
|
|
|
#include "jscntxt.h"
|
2010-12-23 15:10:25 -08:00
|
|
|
#include "jscompartment.h"
|
2013-07-23 17:34:18 -07:00
|
|
|
#include "jslibmath.h"
|
|
|
|
#include "jstypes.h"
|
|
|
|
#include "prmjtime.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
#include "jsobjinlines.h"
|
|
|
|
|
2010-04-07 13:18:50 -07:00
|
|
|
using namespace js;
|
|
|
|
|
2013-03-05 15:43:44 -08:00
|
|
|
using mozilla::Abs;
|
2013-05-01 13:55:13 -07:00
|
|
|
using mozilla::DoubleIsInt32;
|
|
|
|
using mozilla::ExponentComponent;
|
|
|
|
using mozilla::IsFinite;
|
|
|
|
using mozilla::IsInfinite;
|
|
|
|
using mozilla::IsNaN;
|
|
|
|
using mozilla::IsNegative;
|
|
|
|
using mozilla::IsNegativeZero;
|
|
|
|
using mozilla::PositiveInfinity;
|
|
|
|
using mozilla::NegativeInfinity;
|
|
|
|
using mozilla::SpecificNaN;
|
2013-07-15 08:03:14 -07:00
|
|
|
using JS::ToNumber;
|
2013-02-15 19:55:36 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifndef M_E
|
|
|
|
#define M_E 2.7182818284590452354
|
|
|
|
#endif
|
|
|
|
#ifndef M_LOG2E
|
|
|
|
#define M_LOG2E 1.4426950408889634074
|
|
|
|
#endif
|
|
|
|
#ifndef M_LOG10E
|
|
|
|
#define M_LOG10E 0.43429448190325182765
|
|
|
|
#endif
|
|
|
|
#ifndef M_LN2
|
|
|
|
#define M_LN2 0.69314718055994530942
|
|
|
|
#endif
|
|
|
|
#ifndef M_LN10
|
|
|
|
#define M_LN10 2.30258509299404568402
|
|
|
|
#endif
|
|
|
|
#ifndef M_SQRT2
|
|
|
|
#define M_SQRT2 1.41421356237309504880
|
|
|
|
#endif
|
|
|
|
#ifndef M_SQRT1_2
|
|
|
|
#define M_SQRT1_2 0.70710678118654752440
|
|
|
|
#endif
|
|
|
|
|
2013-06-17 18:31:47 -07:00
|
|
|
static const JSConstDoubleSpec math_constants[] = {
|
2007-03-22 10:30:00 -07:00
|
|
|
{M_E, "E", 0, {0,0,0}},
|
|
|
|
{M_LOG2E, "LOG2E", 0, {0,0,0}},
|
|
|
|
{M_LOG10E, "LOG10E", 0, {0,0,0}},
|
|
|
|
{M_LN2, "LN2", 0, {0,0,0}},
|
|
|
|
{M_LN10, "LN10", 0, {0,0,0}},
|
|
|
|
{M_PI, "PI", 0, {0,0,0}},
|
|
|
|
{M_SQRT2, "SQRT2", 0, {0,0,0}},
|
|
|
|
{M_SQRT1_2, "SQRT1_2", 0, {0,0,0}},
|
|
|
|
{0,0,0,{0,0,0}}
|
|
|
|
};
|
|
|
|
|
2010-10-06 12:13:20 -07:00
|
|
|
MathCache::MathCache() {
|
|
|
|
memset(table, 0, sizeof(table));
|
|
|
|
|
|
|
|
/* See comments in lookup(). */
|
2013-05-01 13:55:13 -07:00
|
|
|
JS_ASSERT(IsNegativeZero(-0.0));
|
|
|
|
JS_ASSERT(!IsNegativeZero(+0.0));
|
2010-10-06 12:13:20 -07:00
|
|
|
JS_ASSERT(hash(-0.0) != hash(+0.0));
|
|
|
|
}
|
|
|
|
|
2012-05-15 19:30:28 -07:00
|
|
|
size_t
|
2013-06-23 04:21:01 -07:00
|
|
|
MathCache::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
2012-05-15 19:30:28 -07:00
|
|
|
{
|
|
|
|
return mallocSizeOf(this);
|
|
|
|
}
|
|
|
|
|
2011-09-02 17:23:26 -07:00
|
|
|
Class js::MathClass = {
|
2007-03-22 10:30:00 -07:00
|
|
|
js_Math_str,
|
|
|
|
JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
|
2011-09-20 11:40:24 -07:00
|
|
|
JS_PropertyStub, /* addProperty */
|
2013-04-05 21:19:10 -07:00
|
|
|
JS_DeletePropertyStub, /* delProperty */
|
2011-09-20 11:40:24 -07:00
|
|
|
JS_PropertyStub, /* getProperty */
|
|
|
|
JS_StrictPropertyStub, /* setProperty */
|
|
|
|
JS_EnumerateStub,
|
|
|
|
JS_ResolveStub,
|
|
|
|
JS_ConvertStub
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_abs(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = Abs(x);
|
|
|
|
args.rval().setNumber(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-03 15:56:58 -08:00
|
|
|
double
|
|
|
|
js::math_acos_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
#if defined(SOLARIS) && defined(__GNUC__)
|
|
|
|
if (x < -1 || 1 < x)
|
|
|
|
return js_NaN;
|
|
|
|
#endif
|
|
|
|
return cache->lookup(acos, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-03-03 15:56:58 -08:00
|
|
|
js::math_acos(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = math_acos_impl(mathCache, x);
|
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-03 15:56:58 -08:00
|
|
|
double
|
|
|
|
js::math_asin_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
#if defined(SOLARIS) && defined(__GNUC__)
|
|
|
|
if (x < -1 || 1 < x)
|
|
|
|
return js_NaN;
|
|
|
|
#endif
|
|
|
|
return cache->lookup(asin, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-03-03 15:56:58 -08:00
|
|
|
js::math_asin(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = math_asin_impl(mathCache, x);
|
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-03 15:56:58 -08:00
|
|
|
double
|
|
|
|
js::math_atan_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(atan, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-03-03 15:56:58 -08:00
|
|
|
js::math_atan(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = math_atan_impl(mathCache, x);
|
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-15 02:29:02 -07:00
|
|
|
double
|
2013-06-05 11:36:09 -07:00
|
|
|
js::ecmaAtan2(double y, double x)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-06-19 18:44:10 -07:00
|
|
|
#if defined(_MSC_VER)
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* MSVC's atan2 does not yield the result demanded by ECMA when both x
|
|
|
|
* and y are infinite.
|
|
|
|
* - The result is a multiple of pi/4.
|
2013-06-05 11:36:09 -07:00
|
|
|
* - The sign of y determines the sign of the result.
|
|
|
|
* - The sign of x determines the multiplicator, 1 or 3.
|
2007-03-22 10:30:00 -07:00
|
|
|
*/
|
2013-06-05 11:36:09 -07:00
|
|
|
if (IsInfinite(y) && IsInfinite(x)) {
|
|
|
|
double z = js_copysign(M_PI / 4, y);
|
|
|
|
if (x < 0)
|
2007-03-22 10:30:00 -07:00
|
|
|
z *= 3;
|
2008-12-01 15:14:06 -08:00
|
|
|
return z;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
2008-04-30 10:15:41 -07:00
|
|
|
|
2008-10-22 14:52:14 -07:00
|
|
|
#if defined(SOLARIS) && defined(__GNUC__)
|
2013-06-05 11:36:09 -07:00
|
|
|
if (y == 0) {
|
|
|
|
if (IsNegativeZero(x))
|
|
|
|
return js_copysign(M_PI, y);
|
|
|
|
if (x == 0)
|
|
|
|
return y;
|
2008-04-30 10:15:41 -07:00
|
|
|
}
|
|
|
|
#endif
|
2013-06-05 11:36:09 -07:00
|
|
|
return atan2(y, x);
|
2008-12-01 15:14:06 -08:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-03-15 02:29:02 -07:00
|
|
|
js::math_atan2(JSContext *cx, unsigned argc, Value *vp)
|
2008-12-01 15:14:06 -08:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2008-12-01 15:14:06 -08:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() <= 1) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-12-01 15:14:06 -08:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x, y;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x) || !ToNumber(cx, args[1], &y))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = ecmaAtan2(x, y);
|
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double
|
|
|
|
js_math_ceil_impl(double x)
|
2008-12-17 14:23:53 -08:00
|
|
|
{
|
2008-12-17 22:58:02 -08:00
|
|
|
#ifdef __APPLE__
|
2009-07-27 18:40:12 -07:00
|
|
|
if (x < 0 && x > -1.0)
|
2008-12-17 14:23:53 -08:00
|
|
|
return js_copysign(0, -1);
|
2008-12-17 22:58:02 -08:00
|
|
|
#endif
|
2008-12-17 14:23:53 -08:00
|
|
|
return ceil(x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_ceil(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = js_math_ceil_impl(x);
|
|
|
|
args.rval().setNumber(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-06-15 04:27:04 -07:00
|
|
|
double
|
|
|
|
js::math_cos_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(cos, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-06-15 04:27:04 -07:00
|
|
|
js::math_cos(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = math_cos_impl(mathCache, x);
|
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-03 15:56:58 -08:00
|
|
|
double
|
|
|
|
js::math_exp_impl(MathCache *cache, double x)
|
2010-10-06 12:13:20 -07:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
2013-05-01 13:55:13 -07:00
|
|
|
if (!IsNaN(x)) {
|
2013-03-03 15:56:58 -08:00
|
|
|
if (x == js_PositiveInfinity)
|
2010-10-06 12:13:20 -07:00
|
|
|
return js_PositiveInfinity;
|
2013-03-03 15:56:58 -08:00
|
|
|
if (x == js_NegativeInfinity)
|
2010-10-06 12:13:20 -07:00
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
#endif
|
2013-03-03 15:56:58 -08:00
|
|
|
return cache->lookup(exp, x);
|
2010-10-06 12:13:20 -07:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-03-03 15:56:58 -08:00
|
|
|
js::math_exp(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = math_exp_impl(mathCache, x);
|
|
|
|
args.rval().setNumber(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double
|
|
|
|
js_math_floor_impl(double x)
|
2010-10-18 15:10:52 -07:00
|
|
|
{
|
|
|
|
return floor(x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_floor(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = js_math_floor_impl(x);
|
|
|
|
args.rval().setNumber(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-12-14 10:28:14 -08:00
|
|
|
js::math_imul(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
|
|
|
|
uint32_t a = 0, b = 0;
|
|
|
|
if (args.hasDefined(0) && !ToUint32(cx, args[0], &a))
|
|
|
|
return false;
|
|
|
|
if (args.hasDefined(1) && !ToUint32(cx, args[1], &b))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
uint32_t product = a * b;
|
|
|
|
args.rval().setInt32(product > INT32_MAX
|
|
|
|
? int32_t(INT32_MIN + (product - INT32_MAX - 1))
|
|
|
|
: int32_t(product));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-06-15 04:27:04 -07:00
|
|
|
double
|
|
|
|
js::math_log_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
#if defined(SOLARIS) && defined(__GNUC__)
|
|
|
|
if (x < 0)
|
|
|
|
return js_NaN;
|
|
|
|
#endif
|
|
|
|
return cache->lookup(log, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-06-15 04:27:04 -07:00
|
|
|
js::math_log(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = math_log_impl(mathCache, x);
|
|
|
|
args.rval().setNumber(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_max(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-12-18 17:05:43 -08:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-05-01 13:55:13 -07:00
|
|
|
double maxval = NegativeInfinity();
|
2012-12-18 17:05:43 -08:00
|
|
|
for (unsigned i = 0; i < args.length(); i++) {
|
2013-06-21 18:18:52 -07:00
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[i], &x))
|
2012-12-18 17:05:43 -08:00
|
|
|
return false;
|
|
|
|
// Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
|
2013-05-01 13:55:13 -07:00
|
|
|
if (x > maxval || IsNaN(x) || (x == maxval && IsNegative(maxval)))
|
2012-12-18 17:05:43 -08:00
|
|
|
maxval = x;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-12-18 17:05:43 -08:00
|
|
|
args.rval().setNumber(maxval);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_min(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-12-18 17:05:43 -08:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-05-01 13:55:13 -07:00
|
|
|
double minval = PositiveInfinity();
|
2012-12-18 17:05:43 -08:00
|
|
|
for (unsigned i = 0; i < args.length(); i++) {
|
2013-06-21 18:18:52 -07:00
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[i], &x))
|
2012-12-18 17:05:43 -08:00
|
|
|
return false;
|
|
|
|
// Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
|
2013-05-01 13:55:13 -07:00
|
|
|
if (x < minval || IsNaN(x) || (x == minval && IsNegativeZero(x)))
|
2012-12-18 17:05:43 -08:00
|
|
|
minval = x;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-12-18 17:05:43 -08:00
|
|
|
args.rval().setNumber(minval);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-12-07 14:01:40 -08:00
|
|
|
// Disable PGO for Math.pow() and related functions (see bug 791214).
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("g", off)
|
|
|
|
#endif
|
2012-07-31 20:04:42 -07:00
|
|
|
double
|
|
|
|
js::powi(double x, int y)
|
2010-08-19 14:17:56 -07:00
|
|
|
{
|
2012-03-05 18:43:45 -08:00
|
|
|
unsigned n = (y < 0) ? -y : y;
|
2012-02-24 14:19:52 -08:00
|
|
|
double m = x;
|
|
|
|
double p = 1;
|
2010-08-19 14:17:56 -07:00
|
|
|
while (true) {
|
|
|
|
if ((n & 1) != 0) p *= m;
|
|
|
|
n >>= 1;
|
|
|
|
if (n == 0) {
|
|
|
|
if (y < 0) {
|
|
|
|
// Unfortunately, we have to be careful when p has reached
|
|
|
|
// infinity in the computation, because sometimes the higher
|
|
|
|
// internal precision in the pow() implementation would have
|
|
|
|
// given us a finite p. This happens very rarely.
|
2012-05-19 12:56:17 -07:00
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double result = 1.0 / p;
|
2013-05-01 13:55:13 -07:00
|
|
|
return (result == 0 && IsInfinite(p))
|
2012-02-24 14:19:52 -08:00
|
|
|
? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
|
2010-08-19 14:17:56 -07:00
|
|
|
: result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
m *= m;
|
|
|
|
}
|
|
|
|
}
|
2012-12-07 14:01:40 -08:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("", on)
|
|
|
|
#endif
|
2010-08-19 14:17:56 -07:00
|
|
|
|
2012-12-07 14:01:40 -08:00
|
|
|
// Disable PGO for Math.pow() and related functions (see bug 791214).
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("g", off)
|
|
|
|
#endif
|
2012-07-31 20:04:42 -07:00
|
|
|
double
|
|
|
|
js::ecmaPow(double x, double y)
|
|
|
|
{
|
2013-04-22 03:19:19 -07:00
|
|
|
/*
|
|
|
|
* Use powi if the exponent is an integer-valued double. We don't have to
|
|
|
|
* check for NaN since a comparison with NaN is always false.
|
|
|
|
*/
|
|
|
|
if (int32_t(y) == y)
|
|
|
|
return powi(x, int32_t(y));
|
|
|
|
|
2012-07-31 20:04:42 -07:00
|
|
|
/*
|
|
|
|
* Because C99 and ECMA specify different behavior for pow(),
|
|
|
|
* we need to wrap the libm call to make it ECMA compliant.
|
|
|
|
*/
|
2013-05-01 13:55:13 -07:00
|
|
|
if (!IsFinite(y) && (x == 1.0 || x == -1.0))
|
2012-07-31 20:04:42 -07:00
|
|
|
return js_NaN;
|
2013-03-15 02:29:02 -07:00
|
|
|
/* pow(x, +-0) is always 1, even for x = NaN (MSVC gets this wrong). */
|
|
|
|
if (y == 0)
|
|
|
|
return 1;
|
2012-07-31 20:04:42 -07:00
|
|
|
return pow(x, y);
|
|
|
|
}
|
2012-12-07 14:01:40 -08:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("", on)
|
|
|
|
#endif
|
2012-07-31 20:04:42 -07:00
|
|
|
|
2012-12-07 14:01:40 -08:00
|
|
|
// Disable PGO for Math.pow() and related functions (see bug 791214).
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("g", off)
|
|
|
|
#endif
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_pow(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() <= 1) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x, y;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x) || !ToNumber(cx, args[1], &y))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2010-08-19 14:17:56 -07:00
|
|
|
/*
|
|
|
|
* Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
|
|
|
|
* when x = -0.0, so we have to guard for this.
|
|
|
|
*/
|
2013-05-01 13:55:13 -07:00
|
|
|
if (IsFinite(x) && x != 0.0) {
|
2010-08-19 14:17:56 -07:00
|
|
|
if (y == 0.5) {
|
2013-06-21 18:18:52 -07:00
|
|
|
args.rval().setNumber(sqrt(x));
|
|
|
|
return true;
|
2010-08-19 14:17:56 -07:00
|
|
|
}
|
|
|
|
if (y == -0.5) {
|
2013-06-21 18:18:52 -07:00
|
|
|
args.rval().setNumber(1.0/sqrt(x));
|
|
|
|
return true;
|
2010-08-19 14:17:56 -07:00
|
|
|
}
|
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* pow(x, +-0) is always 1, even for x = NaN. */
|
|
|
|
if (y == 0) {
|
2013-06-21 18:18:52 -07:00
|
|
|
args.rval().setInt32(1);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-08-19 14:17:56 -07:00
|
|
|
|
2013-04-22 03:19:19 -07:00
|
|
|
double z = ecmaPow(x, y);
|
2010-08-19 14:17:56 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
args.rval().setNumber(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-12-07 14:01:40 -08:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("", on)
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-04-18 23:07:18 -07:00
|
|
|
static uint64_t
|
|
|
|
random_generateSeed()
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
uint8_t u8[8];
|
|
|
|
uint32_t u32[2];
|
|
|
|
uint64_t u64;
|
|
|
|
} seed;
|
|
|
|
seed.u64 = 0;
|
|
|
|
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
/*
|
|
|
|
* Our PRNG only uses 48 bits, so calling rand_s() twice to get 64 bits is
|
|
|
|
* probably overkill.
|
|
|
|
*/
|
|
|
|
rand_s(&seed.u32[0]);
|
|
|
|
#elif defined(XP_UNIX)
|
|
|
|
/*
|
|
|
|
* In the unlikely event we can't read /dev/urandom, there's not much we can
|
|
|
|
* do, so just mix in the fd error code and the current time.
|
|
|
|
*/
|
|
|
|
int fd = open("/dev/urandom", O_RDONLY);
|
|
|
|
MOZ_ASSERT(fd >= 0, "Can't open /dev/urandom");
|
|
|
|
if (fd >= 0) {
|
|
|
|
read(fd, seed.u8, mozilla::ArrayLength(seed.u8));
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
seed.u32[0] ^= fd;
|
|
|
|
#else
|
|
|
|
# error "Platform needs to implement random_generateSeed()"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
seed.u32[1] ^= PRMJ_Now();
|
|
|
|
return seed.u64;
|
|
|
|
}
|
|
|
|
|
2012-12-14 12:27:22 -08:00
|
|
|
static const uint64_t RNG_MULTIPLIER = 0x5DEECE66DLL;
|
|
|
|
static const uint64_t RNG_ADDEND = 0xBLL;
|
|
|
|
static const uint64_t RNG_MASK = (1LL << 48) - 1;
|
2012-02-24 14:19:52 -08:00
|
|
|
static const double RNG_DSCALE = double(1LL << 53);
|
2009-08-19 15:23:54 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* Math.random() support, lifted from java.util.Random.java.
|
|
|
|
*/
|
2013-04-18 23:07:18 -07:00
|
|
|
static void
|
|
|
|
random_initState(uint64_t *rngState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-04-18 23:07:18 -07:00
|
|
|
/* Our PRNG only uses 48 bits, so squeeze our entropy into those bits. */
|
|
|
|
uint64_t seed = random_generateSeed();
|
|
|
|
seed ^= (seed >> 16);
|
2012-12-14 12:27:22 -08:00
|
|
|
*rngState = (seed ^ RNG_MULTIPLIER) & RNG_MASK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-04-18 23:07:18 -07:00
|
|
|
uint64_t
|
2012-12-14 12:27:22 -08:00
|
|
|
random_next(uint64_t *rngState, int bits)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-04-18 23:07:18 -07:00
|
|
|
MOZ_ASSERT((*rngState & 0xffff000000000000ULL) == 0, "Bad rngState");
|
|
|
|
MOZ_ASSERT(bits > 0 && bits <= 48, "bits is out of range");
|
|
|
|
|
|
|
|
if (*rngState == 0) {
|
|
|
|
random_initState(rngState);
|
|
|
|
}
|
|
|
|
|
2012-12-14 12:27:22 -08:00
|
|
|
uint64_t nextstate = *rngState * RNG_MULTIPLIER;
|
|
|
|
nextstate += RNG_ADDEND;
|
|
|
|
nextstate &= RNG_MASK;
|
|
|
|
*rngState = nextstate;
|
|
|
|
return nextstate >> (48 - bits);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
static inline double
|
2010-03-18 08:27:26 -07:00
|
|
|
random_nextDouble(JSContext *cx)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-10 14:22:18 -07:00
|
|
|
uint64_t *rng = &cx->compartment()->rngState;
|
2012-12-14 12:27:22 -08:00
|
|
|
return double((random_next(rng, 26) << 27) + random_next(rng, 27)) / RNG_DSCALE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-10-05 12:05:21 -07:00
|
|
|
double
|
|
|
|
math_random_no_outparam(JSContext *cx)
|
|
|
|
{
|
|
|
|
/* Calculate random without memory traffic, for use in the JITs. */
|
|
|
|
return random_nextDouble(cx);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-10-05 12:05:21 -07:00
|
|
|
js_math_random(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-02-24 14:19:52 -08:00
|
|
|
double z = random_nextDouble(cx);
|
2013-06-21 18:18:52 -07:00
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool /* ES5 15.8.2.15. */
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_round(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-12-25 06:16:12 -08:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-12-25 06:16:12 -08:00
|
|
|
|
2011-12-25 06:16:12 -08:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2011-12-25 06:16:12 -08:00
|
|
|
}
|
2011-12-25 06:16:12 -08:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2011-12-25 06:16:12 -08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
int32_t i;
|
2013-05-01 13:55:13 -07:00
|
|
|
if (DoubleIsInt32(x, &i)) {
|
2011-12-25 06:16:12 -08:00
|
|
|
args.rval().setInt32(i);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-01 13:55:13 -07:00
|
|
|
/* Some numbers are so big that adding 0.5 would give the wrong number. */
|
|
|
|
if (ExponentComponent(x) >= 52) {
|
2011-12-25 06:16:12 -08:00
|
|
|
args.rval().setNumber(x);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
args.rval().setNumber(js_copysign(floor(x + 0.5), x));
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-06-15 04:27:04 -07:00
|
|
|
double
|
|
|
|
js::math_sin_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(sin, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-06-15 04:27:04 -07:00
|
|
|
js::math_sin(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = math_sin_impl(mathCache, x);
|
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_sqrt(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = mathCache->lookup(sqrt, x);
|
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-06-15 04:27:04 -07:00
|
|
|
double
|
|
|
|
js::math_tan_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(tan, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2012-06-15 04:27:04 -07:00
|
|
|
js::math_tan(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-21 18:18:52 -07:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2013-06-21 18:18:52 -07:00
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
2013-06-21 18:18:52 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
double z = math_tan_impl(mathCache, x);
|
|
|
|
args.rval().setDouble(z);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-07-15 08:03:14 -07:00
|
|
|
|
|
|
|
typedef double (*UnaryMathFunctionType)(MathCache *cache, double);
|
|
|
|
|
|
|
|
template <UnaryMathFunctionType F>
|
2013-08-08 15:53:04 -07:00
|
|
|
bool math_function(JSContext *cx, unsigned argc, Value *vp)
|
2013-07-15 08:03:14 -07:00
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setNumber(js_NaN);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
double x;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-07-15 08:03:14 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
MathCache *mathCache = cx->runtime()->getMathCache(cx);
|
|
|
|
if (!mathCache)
|
|
|
|
return false;
|
|
|
|
double z = F(mathCache, x);
|
|
|
|
args.rval().setNumber(z);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_log10_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(log10, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_log10(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_log10_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_LOG2
|
|
|
|
double log2(double x)
|
|
|
|
{
|
|
|
|
return log(x) / M_LN2;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_log2_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(log2, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_log2(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_log2_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_LOG1P
|
|
|
|
double log1p(double x)
|
|
|
|
{
|
|
|
|
if (fabs(x) < 1e-4) {
|
|
|
|
/*
|
|
|
|
* Use Taylor approx. log(1 + x) = x - x^2 / 2 + x^3 / 3 - x^4 / 4 with error x^5 / 5
|
|
|
|
* Since |x| < 10^-4, |x|^5 < 10^-20, relative error less than 10^-16
|
|
|
|
*/
|
|
|
|
double z = -(x * x * x * x) / 4 + (x * x * x) / 3 - (x * x) / 2 + x;
|
|
|
|
return z;
|
|
|
|
} else {
|
|
|
|
/* For other large enough values of x use direct computation */
|
|
|
|
return log(1.0 + x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_log1p_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
#ifdef __APPLE__
|
|
|
|
// Ensure that log1p(-0) is -0.
|
|
|
|
if (x == 0)
|
|
|
|
return x;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return cache->lookup(log1p, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_log1p(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_log1p_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_EXPM1
|
|
|
|
double expm1(double x)
|
|
|
|
{
|
|
|
|
/* Special handling for -0 */
|
|
|
|
if (x == 0.0)
|
|
|
|
return x;
|
|
|
|
|
|
|
|
if (fabs(x) < 1e-5) {
|
|
|
|
/*
|
|
|
|
* Use Taylor approx. exp(x) - 1 = x + x^2 / 2 + x^3 / 6 with error x^4 / 24
|
|
|
|
* Since |x| < 10^-5, |x|^4 < 10^-20, relative error less than 10^-15
|
|
|
|
*/
|
|
|
|
double z = (x * x * x) / 6 + (x * x) / 2 + x;
|
|
|
|
return z;
|
|
|
|
} else {
|
|
|
|
/* For other large enough values of x use direct computation */
|
|
|
|
return exp(x) - 1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_expm1_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(expm1, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_expm1(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_expm1_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_SQRT1PM1
|
|
|
|
/* This algorithm computes sqrt(1+x)-1 for small x */
|
|
|
|
double sqrt1pm1(double x)
|
|
|
|
{
|
|
|
|
if (fabs(x) > 0.75)
|
|
|
|
return sqrt(1 + x) - 1;
|
|
|
|
|
|
|
|
return expm1(log1p(x) / 2);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_cosh_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(cosh, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_cosh(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_cosh_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_sinh_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(sinh, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_sinh(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_sinh_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_tanh_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(tanh, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_tanh(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_tanh_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_ACOSH
|
|
|
|
double acosh(double x)
|
|
|
|
{
|
|
|
|
const double SQUARE_ROOT_EPSILON = sqrt(std::numeric_limits<double>::epsilon());
|
|
|
|
|
|
|
|
if ((x - 1) >= SQUARE_ROOT_EPSILON) {
|
|
|
|
if (x > 1 / SQUARE_ROOT_EPSILON) {
|
|
|
|
/*
|
|
|
|
* http://functions.wolfram.com/ElementaryFunctions/ArcCosh/06/01/06/01/0001/
|
|
|
|
* approximation by laurent series in 1/x at 0+ order from -1 to 0
|
|
|
|
*/
|
|
|
|
return log(x) + M_LN2;
|
|
|
|
} else if (x < 1.5) {
|
|
|
|
// This is just a rearrangement of the standard form below
|
|
|
|
// devised to minimize loss of precision when x ~ 1:
|
|
|
|
double y = x - 1;
|
|
|
|
return log1p(y + sqrt(y * y + 2 * y));
|
|
|
|
} else {
|
|
|
|
// http://functions.wolfram.com/ElementaryFunctions/ArcCosh/02/
|
|
|
|
return log(x + sqrt(x * x - 1));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// see http://functions.wolfram.com/ElementaryFunctions/ArcCosh/06/01/04/01/0001/
|
|
|
|
double y = x - 1;
|
|
|
|
// approximation by taylor series in y at 0 up to order 2.
|
|
|
|
// If x is less than 1, sqrt(2 * y) is NaN and the result is NaN.
|
|
|
|
return sqrt(2 * y) * (1 - y / 12 + 3 * y * y / 160);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_acosh_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(acosh, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_acosh(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_acosh_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_ASINH
|
|
|
|
double asinh(double x)
|
|
|
|
{
|
|
|
|
const double SQUARE_ROOT_EPSILON = sqrt(std::numeric_limits<double>::epsilon());
|
|
|
|
const double FOURTH_ROOT_EPSILON = sqrt(SQUARE_ROOT_EPSILON);
|
|
|
|
|
|
|
|
if (x >= FOURTH_ROOT_EPSILON) {
|
|
|
|
if (x > 1 / SQUARE_ROOT_EPSILON)
|
|
|
|
// http://functions.wolfram.com/ElementaryFunctions/ArcSinh/06/01/06/01/0001/
|
|
|
|
// approximation by laurent series in 1/x at 0+ order from -1 to 1
|
|
|
|
return M_LN2 + log(x) + 1 / (4 * x * x);
|
|
|
|
else if (x < 0.5)
|
|
|
|
return log1p(x + sqrt1pm1(x * x));
|
|
|
|
else
|
|
|
|
return log(x + sqrt(x * x + 1));
|
|
|
|
} else if (x <= -FOURTH_ROOT_EPSILON) {
|
|
|
|
return -asinh(-x);
|
|
|
|
} else {
|
|
|
|
// http://functions.wolfram.com/ElementaryFunctions/ArcSinh/06/01/03/01/0001/
|
|
|
|
// approximation by taylor series in x at 0 up to order 2
|
|
|
|
double result = x;
|
|
|
|
|
|
|
|
if (fabs(x) >= SQUARE_ROOT_EPSILON) {
|
|
|
|
double x3 = x * x * x;
|
|
|
|
// approximation by taylor series in x at 0 up to order 4
|
|
|
|
result -= x3 / 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_asinh_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(asinh, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_asinh(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_asinh_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_ATANH
|
|
|
|
double atanh(double x)
|
|
|
|
{
|
|
|
|
const double EPSILON = std::numeric_limits<double>::epsilon();
|
|
|
|
const double SQUARE_ROOT_EPSILON = sqrt(EPSILON);
|
|
|
|
const double FOURTH_ROOT_EPSILON = sqrt(SQUARE_ROOT_EPSILON);
|
|
|
|
|
|
|
|
if (fabs(x) >= FOURTH_ROOT_EPSILON) {
|
|
|
|
// http://functions.wolfram.com/ElementaryFunctions/ArcTanh/02/
|
|
|
|
if (fabs(x) < 0.5)
|
|
|
|
return (log1p(x) - log1p(-x)) / 2;
|
|
|
|
|
|
|
|
return log((1 + x) / (1 - x)) / 2;
|
|
|
|
} else {
|
|
|
|
// http://functions.wolfram.com/ElementaryFunctions/ArcTanh/06/01/03/01/
|
|
|
|
// approximation by taylor series in x at 0 up to order 2
|
|
|
|
double result = x;
|
|
|
|
|
|
|
|
if (fabs(x) >= SQUARE_ROOT_EPSILON) {
|
|
|
|
double x3 = x * x * x;
|
|
|
|
result += x3 / 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_atanh_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(atanh, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_atanh(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_atanh_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_HYPOT
|
|
|
|
double hypot(double x, double y)
|
|
|
|
{
|
|
|
|
if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y))
|
|
|
|
return js_PositiveInfinity;
|
|
|
|
|
|
|
|
if (mozilla::IsNaN(x) || mozilla::IsNaN(y))
|
|
|
|
return js_NaN;
|
|
|
|
|
|
|
|
double xabs = mozilla::Abs(x);
|
|
|
|
double yabs = mozilla::Abs(y);
|
|
|
|
|
|
|
|
double min = std::min(xabs, yabs);
|
|
|
|
double max = std::max(xabs, yabs);
|
|
|
|
|
|
|
|
if (min == 0) {
|
|
|
|
return max;
|
|
|
|
} else {
|
|
|
|
double u = min / max;
|
|
|
|
return max * sqrt(1 + u * u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_hypot_impl(double x, double y)
|
|
|
|
{
|
|
|
|
#ifdef XP_WIN
|
|
|
|
// On Windows, hypot(NaN, Infinity) is NaN. ES6 requires Infinity.
|
|
|
|
if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y))
|
|
|
|
return js_PositiveInfinity;
|
|
|
|
#endif
|
|
|
|
return hypot(x, y);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_hypot(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
if (args.length() < 2) {
|
|
|
|
args.rval().setNumber(js_NaN);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
double x, y;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[0], &x))
|
2013-07-15 08:03:14 -07:00
|
|
|
return false;
|
|
|
|
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[1], &y))
|
2013-07-15 08:03:14 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (args.length() == 2) {
|
|
|
|
args.rval().setNumber(math_hypot_impl(x, y));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* args.length() > 2 */
|
|
|
|
double z;
|
2013-06-26 16:26:45 -07:00
|
|
|
if (!ToNumber(cx, args[2], &z)) {
|
2013-07-15 08:03:14 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
args.rval().setNumber(math_hypot_impl(math_hypot_impl(x, y), z));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_TRUNC
|
|
|
|
double trunc(double x)
|
|
|
|
{
|
|
|
|
return x > 0 ? floor(x) : ceil(x);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_trunc_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(trunc, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_trunc(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_trunc_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
double sign(double x)
|
|
|
|
{
|
|
|
|
if (mozilla::IsNaN(x))
|
|
|
|
return js_NaN;
|
|
|
|
|
|
|
|
return x == 0 ? x : x < 0 ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_sign_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(sign, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_sign(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_sign_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_CBRT
|
|
|
|
double cbrt(double x)
|
|
|
|
{
|
|
|
|
if (x > 0) {
|
|
|
|
return pow(x, 1.0 / 3.0);
|
|
|
|
} else if (x == 0) {
|
|
|
|
return x;
|
|
|
|
} else {
|
|
|
|
return -pow(-x, 1.0 / 3.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
double
|
|
|
|
js::math_cbrt_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(cbrt, x);
|
|
|
|
}
|
|
|
|
|
2013-08-02 00:41:57 -07:00
|
|
|
bool
|
2013-07-15 08:03:14 -07:00
|
|
|
js::math_cbrt(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
return math_function<math_cbrt_impl>(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#if JS_HAS_TOSOURCE
|
2013-08-02 00:41:57 -07:00
|
|
|
static bool
|
2012-02-28 15:11:11 -08:00
|
|
|
math_toSource(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-21 18:18:52 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
args.rval().setString(cx->names().Math);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-04-22 14:15:49 -07:00
|
|
|
static const JSFunctionSpec math_static_methods[] = {
|
2007-03-22 10:30:00 -07:00
|
|
|
#if JS_HAS_TOSOURCE
|
2011-06-10 19:03:57 -07:00
|
|
|
JS_FN(js_toSource_str, math_toSource, 0, 0),
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2011-11-22 14:41:42 -08:00
|
|
|
JS_FN("abs", js_math_abs, 1, 0),
|
|
|
|
JS_FN("acos", math_acos, 1, 0),
|
|
|
|
JS_FN("asin", math_asin, 1, 0),
|
|
|
|
JS_FN("atan", math_atan, 1, 0),
|
|
|
|
JS_FN("atan2", math_atan2, 2, 0),
|
|
|
|
JS_FN("ceil", js_math_ceil, 1, 0),
|
|
|
|
JS_FN("cos", math_cos, 1, 0),
|
|
|
|
JS_FN("exp", math_exp, 1, 0),
|
|
|
|
JS_FN("floor", js_math_floor, 1, 0),
|
2012-12-14 10:28:14 -08:00
|
|
|
JS_FN("imul", math_imul, 2, 0),
|
2011-11-22 14:41:42 -08:00
|
|
|
JS_FN("log", math_log, 1, 0),
|
|
|
|
JS_FN("max", js_math_max, 2, 0),
|
|
|
|
JS_FN("min", js_math_min, 2, 0),
|
|
|
|
JS_FN("pow", js_math_pow, 2, 0),
|
2012-10-05 12:05:21 -07:00
|
|
|
JS_FN("random", js_math_random, 0, 0),
|
2011-11-22 14:41:42 -08:00
|
|
|
JS_FN("round", js_math_round, 1, 0),
|
|
|
|
JS_FN("sin", math_sin, 1, 0),
|
|
|
|
JS_FN("sqrt", js_math_sqrt, 1, 0),
|
|
|
|
JS_FN("tan", math_tan, 1, 0),
|
2013-07-15 08:03:14 -07:00
|
|
|
JS_FN("log10", math_log10, 1, 0),
|
|
|
|
JS_FN("log2", math_log2, 1, 0),
|
|
|
|
JS_FN("log1p", math_log1p, 1, 0),
|
|
|
|
JS_FN("expm1", math_expm1, 1, 0),
|
|
|
|
JS_FN("cosh", math_cosh, 1, 0),
|
|
|
|
JS_FN("sinh", math_sinh, 1, 0),
|
|
|
|
JS_FN("tanh", math_tanh, 1, 0),
|
|
|
|
JS_FN("acosh", math_acosh, 1, 0),
|
|
|
|
JS_FN("asinh", math_asinh, 1, 0),
|
|
|
|
JS_FN("atanh", math_atanh, 1, 0),
|
|
|
|
JS_FN("hypot", math_hypot, 2, 0),
|
|
|
|
JS_FN("trunc", math_trunc, 1, 0),
|
|
|
|
JS_FN("sign", math_sign, 1, 0),
|
|
|
|
JS_FN("cbrt", math_cbrt, 1, 0),
|
2007-08-01 21:33:52 -07:00
|
|
|
JS_FS_END
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
JSObject *
|
2012-09-20 22:17:49 -07:00
|
|
|
js_InitMathClass(JSContext *cx, HandleObject obj)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-01-28 11:01:54 -08:00
|
|
|
RootedObject Math(cx, NewObjectWithClassProto(cx, &MathClass, NULL, obj, SingletonObject));
|
|
|
|
if (!Math)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NULL;
|
2010-12-18 20:44:51 -08:00
|
|
|
|
2011-03-06 22:57:13 -08:00
|
|
|
if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
|
|
|
|
JS_PropertyStub, JS_StrictPropertyStub, 0)) {
|
2008-08-20 12:58:07 -07:00
|
|
|
return NULL;
|
2008-12-02 22:39:10 -08:00
|
|
|
}
|
2008-08-20 12:58:07 -07:00
|
|
|
|
2011-05-16 16:15:37 -07:00
|
|
|
if (!JS_DefineFunctions(cx, Math, math_static_methods))
|
2007-03-22 10:30:00 -07:00
|
|
|
return NULL;
|
|
|
|
if (!JS_DefineConstDoubles(cx, Math, math_constants))
|
|
|
|
return NULL;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-09-02 17:23:26 -07:00
|
|
|
MarkStandardClassInitializedNoProto(obj, &MathClass);
|
Bug 642772: Don't recreate a class during enumeration, if it has been deleted (r=bhackett)
In SM, classes are lazily resolved. If we detect that a class about to be used
has not yet been resolved, then we resolve it. However, the way that we decided
that they were resolved was broken. If the global object had a String property,
then it had been resolved. So what happened when we deleted the String
property? Well, it got resolved again.
Instead of using the String property of the global object, we now use the
contructor slot on the global object. This works fine for String, but some
classes don't have a constructor, like Math and JSON. For those classes, we set
the constructor slot to True. In either case, we can now tell that a class is
resolved if the constructor slot in not Undefined.
2011-04-27 04:13:56 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return Math;
|
|
|
|
}
|