netscape-revival
mocha/src/mo_math.c
/*
** Standard Mocha math functions.
**
** Brendan Eich, 11/15/95
*/
#include <math.h>
#include <stdlib.h>
#include "prlong.h"
#include "prtime.h"
#include "mo_cntxt.h"
#include "mocha.h"
#include "mochaapi.h"
#include "mochalib.h"
enum math_slot {
MATH_E,
MATH_LOG2E,
MATH_LOG10E,
MATH_LN2,
MATH_LN10,
MATH_PI,
MATH_SQRT2,
MATH_SQRT1_2,
MATH_MAX
};
#ifndef M_E
#define M_E 2.7182818284590452354
#define M_LOG2E 1.4426950408889634074
#define M_LOG10E 0.43429448190325182765
#define M_LN2 0.69314718055994530942
#define M_LN10 2.30258509299404568402
#define M_PI 3.14159265358979323846
#define M_SQRT2 1.41421356237309504880
#define M_SQRT1_2 0.70710678118654752440
#endif
static MochaBoolean
math_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum *dp)
{
switch (slot) {
case MATH_E:
dp->tag = MOCHA_NUMBER;
dp->u.fval = M_E;
break;
case MATH_LOG2E:
dp->tag = MOCHA_NUMBER;
dp->u.fval = M_LOG2E;
break;
case MATH_LOG10E:
dp->tag = MOCHA_NUMBER;
dp->u.fval = M_LOG10E;
break;
case MATH_LN2:
dp->tag = MOCHA_NUMBER;
dp->u.fval = M_LN2;
break;
case MATH_LN10:
dp->tag = MOCHA_NUMBER;
dp->u.fval = M_LN10;
break;
case MATH_PI:
dp->tag = MOCHA_NUMBER;
dp->u.fval = M_PI;
break;
case MATH_SQRT2:
dp->tag = MOCHA_NUMBER;
dp->u.fval = M_SQRT2;
break;
case MATH_SQRT1_2:
dp->tag = MOCHA_NUMBER;
dp->u.fval = M_SQRT1_2;
break;
}
return MOCHA_TRUE;
}
static MochaPropertySpec math_static_props[] = {
{"E", MATH_E, MDF_READONLY, math_get_property},
{"LOG2E", MATH_LOG2E, MDF_READONLY, math_get_property},
{"LOG10E", MATH_LOG10E, MDF_READONLY, math_get_property},
{"LN2", MATH_LN2, MDF_READONLY, math_get_property},
{"LN10", MATH_LN10, MDF_READONLY, math_get_property},
{"PI", MATH_PI, MDF_READONLY, math_get_property},
{"SQRT2", MATH_SQRT2, MDF_READONLY, math_get_property},
{"SQRT1_2", MATH_SQRT1_2, MDF_READONLY, math_get_property},
{0}
};
static MochaClass math_class = {
"Math",
math_get_property, math_get_property, MOCHA_ListPropStub,
MOCHA_ResolveStub, MOCHA_ConvertStub, MOCHA_FinalizeStub
};
static MochaBoolean
math_abs(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = (x < 0) ? -x : x;
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_acos(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = acos(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_asin(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = asin(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_atan(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = atan(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_atan2(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, y, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
if (!mocha_DatumToNumber(mc, argv[1], &y))
return MOCHA_FALSE;
z = atan2(x, y);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_ceil(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = ceil(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_cos(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = cos(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_exp(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = exp(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_floor(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = floor(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_log(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = log(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_max(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, y, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
if (!mocha_DatumToNumber(mc, argv[1], &y))
return MOCHA_FALSE;
z = (x > y) ? x : y;
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_min(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, y, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
if (!mocha_DatumToNumber(mc, argv[1], &y))
return MOCHA_FALSE;
z = (x < y) ? x : y;
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_pow(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, y, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
if (!mocha_DatumToNumber(mc, argv[1], &y))
return MOCHA_FALSE;
z = pow(x, y);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
/*
** Math.random() support, lifted from classsrc/java/util/Random.java in the
** ns/sun-java tree.
*/
static MochaBoolean random_initialized;
static int64 random_multiplier;
static int64 random_addend;
static int64 random_mask;
static int64 random_seed;
static MochaFloat random_dscale;
static void
random_setSeed(int64 seed)
{
int64 tmp;
LL_I2L(tmp, 1000);
LL_DIV(seed, seed, tmp);
LL_XOR(tmp, seed, random_multiplier);
LL_AND(random_seed, tmp, random_mask);
}
static void
random_init(void)
{
int64 tmp, tmp2;
/* Do at most once. */
if (random_initialized)
return;
random_initialized = MOCHA_TRUE;
/* random_multiplier = 0x5DEECE66DL */
LL_ISHL(tmp, 0x5D, 32);
LL_UI2L(tmp2, 0xEECE66DL);
LL_OR(random_multiplier, tmp, tmp2);
/* random_addend = 0xBL */
LL_I2L(random_addend, 0xBL);
/* random_mask = (1L << 48) - 1 */
LL_I2L(tmp, 1);
LL_SHL(tmp2, tmp, 48);
LL_SUB(random_mask, tmp2, tmp);
/* random_dscale = (MochaFloat)(1L << 54) */
LL_SHL(tmp2, tmp, 54);
LL_L2D(random_dscale, tmp2);
/* Finally, set the seed from current time. */
random_setSeed(PR_Now());
}
static uint32
random_next(int bits)
{
int64 nextseed, tmp;
uint32 retval;
LL_MUL(nextseed, random_seed, random_multiplier);
LL_ADD(nextseed, nextseed, random_addend);
LL_AND(nextseed, nextseed, random_mask);
random_seed = nextseed;
LL_USHR(tmp, nextseed, 48 - bits);
LL_L2I(retval, tmp);
return retval;
}
static MochaFloat
random_nextDouble(void)
{
int64 tmp, tmp2;
MochaFloat fval;
LL_ISHL(tmp, random_next(27), 27);
LL_UI2L(tmp2, random_next(27));
LL_ADD(tmp, tmp, tmp2);
LL_L2D(fval, tmp);
return fval / random_dscale;
}
static MochaBoolean
math_random(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat z;
random_init();
z = random_nextDouble();
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_round(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = floor(x + 0.5);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_sin(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = sin(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_sqrt(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = sqrt(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaBoolean
math_tan(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaFloat x, z;
if (!mocha_DatumToNumber(mc, argv[0], &x))
return MOCHA_FALSE;
z = tan(x);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, z);
return MOCHA_TRUE;
}
static MochaFunctionSpec math_static_methods[] = {
{"abs", math_abs, 1},
{"acos", math_acos, 1},
{"asin", math_asin, 1},
{"atan", math_atan, 1},
{"atan2", math_atan2, 2},
{"ceil", math_ceil, 1},
{"cos", math_cos, 1},
{"exp", math_exp, 1},
{"floor", math_floor, 1},
{"log", math_log, 1},
{"max", math_max, 2},
{"min", math_min, 2},
{"pow", math_pow, 2},
{"random", math_random, 0},
{"round", math_round, 1},
{"sin", math_sin, 1},
{"sqrt", math_sqrt, 1},
{"tan", math_tan, 1},
{0}
};
static MochaBoolean
Math(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
return MOCHA_TRUE;
}
MochaObject *
mocha_InitMathClass(MochaContext *mc, MochaObject *obj)
{
return MOCHA_InitClass(mc, obj, &math_class, 0, Math, 0,
0, 0, math_static_props, math_static_methods);
}