[builtins] Introduce proper Float64Log2 and Float64Log10 operators.
BUG=v8:5095 Review-Url: https://codereview.chromium.org/2063693002 Cr-Commit-Position: refs/heads/master@{#37035}
This commit is contained in:
parent
76a5144354
commit
d9bf520a22
@ -1638,6 +1638,16 @@ ExternalReference ExternalReference::ieee754_log1p_function(Isolate* isolate) {
|
||||
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log1p), BUILTIN_FP_CALL));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::ieee754_log2_function(Isolate* isolate) {
|
||||
return ExternalReference(
|
||||
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log2), BUILTIN_FP_CALL));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::ieee754_log10_function(Isolate* isolate) {
|
||||
return ExternalReference(
|
||||
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log10), BUILTIN_FP_CALL));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::math_exp_constants(int constant_index) {
|
||||
DCHECK(math_exp_data_initialized);
|
||||
return ExternalReference(
|
||||
|
@ -1046,6 +1046,8 @@ class ExternalReference BASE_EMBEDDED {
|
||||
static ExternalReference ieee754_atan2_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log1p_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log2_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log10_function(Isolate* isolate);
|
||||
|
||||
static ExternalReference math_exp_constants(int constant_index);
|
||||
static ExternalReference math_exp_log_table();
|
||||
|
@ -397,7 +397,7 @@ double atan2(double y, double x) {
|
||||
*
|
||||
* Method :
|
||||
* 1. Argument Reduction: find k and f such that
|
||||
* x = 2^k * (1+f),
|
||||
* x = 2^k * (1+f),
|
||||
* where sqrt(2)/2 < 1+f < sqrt(2) .
|
||||
*
|
||||
* 2. Approximation of log(1+f).
|
||||
@ -685,6 +685,307 @@ double log1p(double x) {
|
||||
return k * ln2_hi - ((hfsq - (s * (hfsq + R) + (k * ln2_lo + c))) - f);
|
||||
}
|
||||
|
||||
/*
|
||||
* k_log1p(f):
|
||||
* Return log(1+f) - f for 1+f in ~[sqrt(2)/2, sqrt(2)].
|
||||
*
|
||||
* The following describes the overall strategy for computing
|
||||
* logarithms in base e. The argument reduction and adding the final
|
||||
* term of the polynomial are done by the caller for increased accuracy
|
||||
* when different bases are used.
|
||||
*
|
||||
* Method :
|
||||
* 1. Argument Reduction: find k and f such that
|
||||
* x = 2^k * (1+f),
|
||||
* where sqrt(2)/2 < 1+f < sqrt(2) .
|
||||
*
|
||||
* 2. Approximation of log(1+f).
|
||||
* Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
|
||||
* = 2s + 2/3 s**3 + 2/5 s**5 + .....,
|
||||
* = 2s + s*R
|
||||
* We use a special Reme algorithm on [0,0.1716] to generate
|
||||
* a polynomial of degree 14 to approximate R The maximum error
|
||||
* of this polynomial approximation is bounded by 2**-58.45. In
|
||||
* other words,
|
||||
* 2 4 6 8 10 12 14
|
||||
* R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s
|
||||
* (the values of Lg1 to Lg7 are listed in the program)
|
||||
* and
|
||||
* | 2 14 | -58.45
|
||||
* | Lg1*s +...+Lg7*s - R(z) | <= 2
|
||||
* | |
|
||||
* Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
|
||||
* In order to guarantee error in log below 1ulp, we compute log
|
||||
* by
|
||||
* log(1+f) = f - s*(f - R) (if f is not too large)
|
||||
* log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
|
||||
*
|
||||
* 3. Finally, log(x) = k*ln2 + log(1+f).
|
||||
* = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
|
||||
* Here ln2 is split into two floating point number:
|
||||
* ln2_hi + ln2_lo,
|
||||
* where n*ln2_hi is always exact for |n| < 2000.
|
||||
*
|
||||
* Special cases:
|
||||
* log(x) is NaN with signal if x < 0 (including -INF) ;
|
||||
* log(+INF) is +INF; log(0) is -INF with signal;
|
||||
* log(NaN) is that NaN with no signal.
|
||||
*
|
||||
* Accuracy:
|
||||
* according to an error analysis, the error is always less than
|
||||
* 1 ulp (unit in the last place).
|
||||
*
|
||||
* Constants:
|
||||
* The hexadecimal values are the intended ones for the following
|
||||
* constants. The decimal values may be used, provided that the
|
||||
* compiler will convert from decimal to binary accurately enough
|
||||
* to produce the hexadecimal values shown.
|
||||
*/
|
||||
|
||||
static const double Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
|
||||
Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
|
||||
Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
|
||||
Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
|
||||
Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
|
||||
Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
|
||||
Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
|
||||
/*
|
||||
* We always inline k_log1p(), since doing so produces a
|
||||
* substantial performance improvement (~40% on amd64).
|
||||
*/
|
||||
static inline double k_log1p(double f) {
|
||||
double hfsq, s, z, R, w, t1, t2;
|
||||
|
||||
s = f / (2.0 + f);
|
||||
z = s * s;
|
||||
w = z * z;
|
||||
t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
|
||||
t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
|
||||
R = t2 + t1;
|
||||
hfsq = 0.5 * f * f;
|
||||
return s * (hfsq + R);
|
||||
}
|
||||
|
||||
// ES6 draft 09-27-13, section 20.2.2.22.
|
||||
// Return the base 2 logarithm of x
|
||||
//
|
||||
// fdlibm does not have an explicit log2 function, but fdlibm's pow
|
||||
// function does implement an accurate log2 function as part of the
|
||||
// pow implementation. This extracts the core parts of that as a
|
||||
// separate log2 function.
|
||||
//
|
||||
// Method:
|
||||
// Compute log2(x) in two pieces:
|
||||
// log2(x) = w1 + w2
|
||||
// where w1 has 53-24 = 29 bits of trailing zeroes.
|
||||
double log2(double x) {
|
||||
static const double
|
||||
bp[] = {1.0, 1.5},
|
||||
dp_h[] = {0.0, 5.84962487220764160156e-01}, /* 0x3FE2B803, 0x40000000 */
|
||||
dp_l[] = {0.0, 1.35003920212974897128e-08}, /* 0x3E4CFDEB, 0x43CFD006 */
|
||||
zero = 0.0, one = 1.0,
|
||||
// Polynomial coefficients for (3/2)*(log2(x) - 2*s - 2/3*s^3)
|
||||
L1 = 5.99999999999994648725e-01, L2 = 4.28571428578550184252e-01,
|
||||
L3 = 3.33333329818377432918e-01, L4 = 2.72728123808534006489e-01,
|
||||
L5 = 2.30660745775561754067e-01, L6 = 2.06975017800338417784e-01,
|
||||
// cp = 2/(3*ln(2)). Note that cp_h + cp_l is cp, but with more accuracy.
|
||||
cp = 9.61796693925975554329e-01, cp_h = 9.61796700954437255859e-01,
|
||||
cp_l = -7.02846165095275826516e-09, two53 = 9007199254740992, /* 2^53 */
|
||||
two54 = 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */
|
||||
|
||||
static volatile double vzero = 0.0;
|
||||
double ax, z_h, z_l, p_h, p_l;
|
||||
double t1, t2, r, t, u, v;
|
||||
int32_t j, k, n;
|
||||
int32_t ix, hx;
|
||||
u_int32_t lx;
|
||||
|
||||
EXTRACT_WORDS(hx, lx, x);
|
||||
ix = hx & 0x7fffffff;
|
||||
|
||||
// Handle special cases.
|
||||
// log2(+/- 0) = -Infinity
|
||||
if ((ix | lx) == 0) return -two54 / vzero; /* log(+-0)=-inf */
|
||||
|
||||
// log(x) = NaN, if x < 0
|
||||
if (hx < 0) return (x - x) / zero; /* log(-#) = NaN */
|
||||
|
||||
// log2(Infinity) = Infinity, log2(NaN) = NaN
|
||||
if (ix >= 0x7ff00000) return x;
|
||||
|
||||
ax = fabs(x);
|
||||
|
||||
double ss, s2, s_h, s_l, t_h, t_l;
|
||||
n = 0;
|
||||
|
||||
/* take care subnormal number */
|
||||
if (ix < 0x00100000) {
|
||||
ax *= two53;
|
||||
n -= 53;
|
||||
GET_HIGH_WORD(ix, ax);
|
||||
}
|
||||
|
||||
n += ((ix) >> 20) - 0x3ff;
|
||||
j = ix & 0x000fffff;
|
||||
|
||||
/* determine interval */
|
||||
ix = j | 0x3ff00000; /* normalize ix */
|
||||
if (j <= 0x3988E) {
|
||||
k = 0; /* |x|<sqrt(3/2) */
|
||||
} else if (j < 0xBB67A) {
|
||||
k = 1; /* |x|<sqrt(3) */
|
||||
} else {
|
||||
k = 0;
|
||||
n += 1;
|
||||
ix -= 0x00100000;
|
||||
}
|
||||
SET_HIGH_WORD(ax, ix);
|
||||
|
||||
/* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
|
||||
u = ax - bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
|
||||
v = one / (ax + bp[k]);
|
||||
ss = u * v;
|
||||
s_h = ss;
|
||||
SET_LOW_WORD(s_h, 0);
|
||||
/* t_h=ax+bp[k] High */
|
||||
t_h = zero;
|
||||
SET_HIGH_WORD(t_h, ((ix >> 1) | 0x20000000) + 0x00080000 + (k << 18));
|
||||
t_l = ax - (t_h - bp[k]);
|
||||
s_l = v * ((u - s_h * t_h) - s_h * t_l);
|
||||
/* compute log(ax) */
|
||||
s2 = ss * ss;
|
||||
r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6)))));
|
||||
r += s_l * (s_h + ss);
|
||||
s2 = s_h * s_h;
|
||||
t_h = 3.0 + s2 + r;
|
||||
SET_LOW_WORD(t_h, 0);
|
||||
t_l = r - ((t_h - 3.0) - s2);
|
||||
/* u+v = ss*(1+...) */
|
||||
u = s_h * t_h;
|
||||
v = s_l * t_h + t_l * ss;
|
||||
/* 2/(3log2)*(ss+...) */
|
||||
p_h = u + v;
|
||||
SET_LOW_WORD(p_h, 0);
|
||||
p_l = v - (p_h - u);
|
||||
z_h = cp_h * p_h; /* cp_h+cp_l = 2/(3*log2) */
|
||||
z_l = cp_l * p_h + p_l * cp + dp_l[k];
|
||||
/* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
|
||||
t = static_cast<double>(n);
|
||||
t1 = (((z_h + z_l) + dp_h[k]) + t);
|
||||
SET_LOW_WORD(t1, 0);
|
||||
t2 = z_l - (((t1 - t) - dp_h[k]) - z_h);
|
||||
|
||||
// t1 + t2 = log2(ax), sum up because we do not care about extra precision.
|
||||
return t1 + t2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the base 10 logarithm of x. See e_log.c and k_log.h for most
|
||||
* comments.
|
||||
*
|
||||
* log10(x) = (f - 0.5*f*f + k_log1p(f)) / ln10 + k * log10(2)
|
||||
* in not-quite-routine extra precision.
|
||||
*/
|
||||
double log10Old(double x) {
|
||||
static const double
|
||||
two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
|
||||
ivln10hi = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */
|
||||
ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */
|
||||
log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
|
||||
log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
|
||||
|
||||
static const double zero = 0.0;
|
||||
static volatile double vzero = 0.0;
|
||||
|
||||
double f, hfsq, hi, lo, r, val_hi, val_lo, w, y, y2;
|
||||
int32_t i, k, hx;
|
||||
u_int32_t lx;
|
||||
|
||||
EXTRACT_WORDS(hx, lx, x);
|
||||
|
||||
k = 0;
|
||||
if (hx < 0x00100000) { /* x < 2**-1022 */
|
||||
if (((hx & 0x7fffffff) | lx) == 0)
|
||||
return -two54 / vzero; /* log(+-0)=-inf */
|
||||
if (hx < 0) return (x - x) / zero; /* log(-#) = NaN */
|
||||
k -= 54;
|
||||
x *= two54; /* subnormal number, scale up x */
|
||||
GET_HIGH_WORD(hx, x);
|
||||
}
|
||||
if (hx >= 0x7ff00000) return x + x;
|
||||
if (hx == 0x3ff00000 && lx == 0) return zero; /* log(1) = +0 */
|
||||
k += (hx >> 20) - 1023;
|
||||
hx &= 0x000fffff;
|
||||
i = (hx + 0x95f64) & 0x100000;
|
||||
SET_HIGH_WORD(x, hx | (i ^ 0x3ff00000)); /* normalize x or x/2 */
|
||||
k += (i >> 20);
|
||||
y = static_cast<double>(k);
|
||||
f = x - 1.0;
|
||||
hfsq = 0.5 * f * f;
|
||||
r = k_log1p(f);
|
||||
|
||||
/* See e_log2.c for most details. */
|
||||
hi = f - hfsq;
|
||||
SET_LOW_WORD(hi, 0);
|
||||
lo = (f - hi) - hfsq + r;
|
||||
val_hi = hi * ivln10hi;
|
||||
y2 = y * log10_2hi;
|
||||
val_lo = y * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi;
|
||||
|
||||
/*
|
||||
* Extra precision in for adding y*log10_2hi is not strictly needed
|
||||
* since there is no very large cancellation near x = sqrt(2) or
|
||||
* x = 1/sqrt(2), but we do it anyway since it costs little on CPUs
|
||||
* with some parallelism and it reduces the error for many args.
|
||||
*/
|
||||
w = y2 + val_hi;
|
||||
val_lo += (y2 - w) + val_hi;
|
||||
val_hi = w;
|
||||
|
||||
return val_lo + val_hi;
|
||||
}
|
||||
|
||||
double log10(double x) {
|
||||
static const double
|
||||
two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
|
||||
ivln10 = 4.34294481903251816668e-01,
|
||||
log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
|
||||
log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
|
||||
|
||||
static const double zero = 0.0;
|
||||
static volatile double vzero = 0.0;
|
||||
|
||||
double y;
|
||||
int32_t i, k, hx;
|
||||
u_int32_t lx;
|
||||
|
||||
EXTRACT_WORDS(hx, lx, x);
|
||||
|
||||
k = 0;
|
||||
if (hx < 0x00100000) { /* x < 2**-1022 */
|
||||
if (((hx & 0x7fffffff) | lx) == 0)
|
||||
return -two54 / vzero; /* log(+-0)=-inf */
|
||||
if (hx < 0) return (x - x) / zero; /* log(-#) = NaN */
|
||||
k -= 54;
|
||||
x *= two54; /* subnormal number, scale up x */
|
||||
GET_HIGH_WORD(hx, x);
|
||||
GET_LOW_WORD(lx, x);
|
||||
}
|
||||
if (hx >= 0x7ff00000) return x + x;
|
||||
if (hx == 0x3ff00000 && lx == 0) return zero; /* log(1) = +0 */
|
||||
k += (hx >> 20) - 1023;
|
||||
|
||||
i = (k & 0x80000000) >> 31;
|
||||
hx = (hx & 0x000fffff) | ((0x3ff - i) << 20);
|
||||
y = k + i;
|
||||
SET_HIGH_WORD(x, hx);
|
||||
SET_LOW_WORD(x, lx);
|
||||
|
||||
double z = y * log10_2lo + ivln10 * log(x);
|
||||
return z + y * log10_2hi;
|
||||
}
|
||||
|
||||
} // namespace ieee754
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
@ -24,6 +24,12 @@ double log(double x);
|
||||
// accurate even if the value of |x| is near zero.
|
||||
double log1p(double x);
|
||||
|
||||
// Return the base 2 logarithm of |x|.
|
||||
double log2(double x);
|
||||
|
||||
// Return the base 10 logarithm of |x|.
|
||||
double log10(double x);
|
||||
|
||||
} // namespace ieee754
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
@ -1685,6 +1685,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
SimpleInstallFunction(math, "log", Builtins::kMathLog, 1, true);
|
||||
native_context()->set_math_log(*math_log);
|
||||
SimpleInstallFunction(math, "log1p", Builtins::kMathLog1p, 1, true);
|
||||
SimpleInstallFunction(math, "log2", Builtins::kMathLog2, 1, true);
|
||||
SimpleInstallFunction(math, "log10", Builtins::kMathLog10, 1, true);
|
||||
SimpleInstallFunction(math, "max", Builtins::kMathMax, 2, false);
|
||||
SimpleInstallFunction(math, "min", Builtins::kMathMin, 2, false);
|
||||
SimpleInstallFunction(math, "round", Builtins::kMathRound, 1, true);
|
||||
|
@ -2503,6 +2503,30 @@ void Builtins::Generate_MathLog1p(CodeStubAssembler* assembler) {
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.23 Math.log2 ( x )
|
||||
void Builtins::Generate_MathLog2(CodeStubAssembler* assembler) {
|
||||
using compiler::Node;
|
||||
|
||||
Node* x = assembler->Parameter(1);
|
||||
Node* context = assembler->Parameter(4);
|
||||
Node* x_value = assembler->TruncateTaggedToFloat64(context, x);
|
||||
Node* value = assembler->Float64Log2(x_value);
|
||||
Node* result = assembler->ChangeFloat64ToTagged(value);
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.22 Math.log10 ( x )
|
||||
void Builtins::Generate_MathLog10(CodeStubAssembler* assembler) {
|
||||
using compiler::Node;
|
||||
|
||||
Node* x = assembler->Parameter(1);
|
||||
Node* context = assembler->Parameter(4);
|
||||
Node* x_value = assembler->TruncateTaggedToFloat64(context, x);
|
||||
Node* value = assembler->Float64Log10(x_value);
|
||||
Node* result = assembler->ChangeFloat64ToTagged(value);
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.28 Math.round ( x )
|
||||
void Builtins::Generate_MathRound(CodeStubAssembler* assembler) {
|
||||
Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Round);
|
||||
|
@ -323,6 +323,8 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
|
||||
V(MathFloor, 2) \
|
||||
V(MathLog, 2) \
|
||||
V(MathLog1p, 2) \
|
||||
V(MathLog2, 2) \
|
||||
V(MathLog10, 2) \
|
||||
V(MathRound, 2) \
|
||||
V(MathSqrt, 2) \
|
||||
V(MathTrunc, 2) \
|
||||
@ -638,6 +640,10 @@ class Builtins {
|
||||
static void Generate_MathLog(CodeStubAssembler* assembler);
|
||||
// ES6 section 20.2.2.21 Math.log ( x )
|
||||
static void Generate_MathLog1p(CodeStubAssembler* assembler);
|
||||
|
||||
static void Generate_MathLog2(CodeStubAssembler* assembler);
|
||||
static void Generate_MathLog10(CodeStubAssembler* assembler);
|
||||
|
||||
enum class MathMaxMinKind { kMax, kMin };
|
||||
static void Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind);
|
||||
// ES6 section 20.2.2.24 Math.max ( value1, value2 , ...values )
|
||||
|
@ -715,6 +715,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
case kIeee754Float64Log2:
|
||||
ASSEMBLE_IEEE754_UNOP(log2);
|
||||
break;
|
||||
case kIeee754Float64Log10:
|
||||
ASSEMBLE_IEEE754_UNOP(log10);
|
||||
break;
|
||||
case kArmAdd:
|
||||
__ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
|
||||
i.OutputSBit());
|
||||
|
@ -819,6 +819,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
case kIeee754Float64Log2:
|
||||
ASSEMBLE_IEEE754_UNOP(log2);
|
||||
break;
|
||||
case kIeee754Float64Log10:
|
||||
ASSEMBLE_IEEE754_UNOP(log10);
|
||||
break;
|
||||
case kArm64Float32RoundDown:
|
||||
__ Frintm(i.OutputFloat32Register(), i.InputFloat32Register(0));
|
||||
break;
|
||||
|
@ -110,6 +110,8 @@ class Schedule;
|
||||
V(Float64Atan) \
|
||||
V(Float64Log) \
|
||||
V(Float64Log1p) \
|
||||
V(Float64Log2) \
|
||||
V(Float64Log10) \
|
||||
V(Float64Neg) \
|
||||
V(Float64Sqrt) \
|
||||
V(Float64ExtractLowWord32) \
|
||||
|
@ -661,6 +661,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
case kIeee754Float64Log2:
|
||||
ASSEMBLE_IEEE754_UNOP(log2);
|
||||
break;
|
||||
case kIeee754Float64Log10:
|
||||
ASSEMBLE_IEEE754_UNOP(log10);
|
||||
break;
|
||||
case kIA32Add:
|
||||
if (HasImmediateInput(instr, 1)) {
|
||||
__ add(i.InputOperand(0), i.InputImmediate(1));
|
||||
|
@ -92,7 +92,9 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny };
|
||||
V(Ieee754Float64Atan) \
|
||||
V(Ieee754Float64Atan2) \
|
||||
V(Ieee754Float64Log) \
|
||||
V(Ieee754Float64Log1p)
|
||||
V(Ieee754Float64Log1p) \
|
||||
V(Ieee754Float64Log2) \
|
||||
V(Ieee754Float64Log10)
|
||||
|
||||
#define ARCH_OPCODE_LIST(V) \
|
||||
COMMON_ARCH_OPCODE_LIST(V) \
|
||||
|
@ -228,6 +228,8 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
|
||||
case kIeee754Float64Atan2:
|
||||
case kIeee754Float64Log:
|
||||
case kIeee754Float64Log1p:
|
||||
case kIeee754Float64Log2:
|
||||
case kIeee754Float64Log10:
|
||||
return kNoOpcodeFlags;
|
||||
|
||||
case kArchStackPointer:
|
||||
|
@ -1142,6 +1142,10 @@ void InstructionSelector::VisitNode(Node* node) {
|
||||
return MarkAsFloat64(node), VisitFloat64Log(node);
|
||||
case IrOpcode::kFloat64Log1p:
|
||||
return MarkAsFloat64(node), VisitFloat64Log1p(node);
|
||||
case IrOpcode::kFloat64Log2:
|
||||
return MarkAsFloat64(node), VisitFloat64Log2(node);
|
||||
case IrOpcode::kFloat64Log10:
|
||||
return MarkAsFloat64(node), VisitFloat64Log10(node);
|
||||
case IrOpcode::kFloat64Sqrt:
|
||||
return MarkAsFloat64(node), VisitFloat64Sqrt(node);
|
||||
case IrOpcode::kFloat64Equal:
|
||||
@ -1263,6 +1267,14 @@ void InstructionSelector::VisitFloat64Log1p(Node* node) {
|
||||
VisitFloat64Ieee754Unop(node, kIeee754Float64Log1p);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log2(Node* node) {
|
||||
VisitFloat64Ieee754Unop(node, kIeee754Float64Log2);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log10(Node* node) {
|
||||
VisitFloat64Ieee754Unop(node, kIeee754Float64Log10);
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitTableSwitch(const SwitchInfo& sw,
|
||||
InstructionOperand& index_operand) {
|
||||
OperandGenerator g(this);
|
||||
|
@ -259,6 +259,28 @@ Reduction JSBuiltinReducer::ReduceMathMin(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.23 Math.log2 ( x )
|
||||
Reduction JSBuiltinReducer::ReduceMathLog2(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
if (r.InputsMatchOne(Type::Number())) {
|
||||
// Math.log2(a:number) -> NumberLog(a)
|
||||
Node* value = graph()->NewNode(simplified()->NumberLog2(), r.left());
|
||||
return Replace(value);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.22 Math.log10 ( x )
|
||||
Reduction JSBuiltinReducer::ReduceMathLog10(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
if (r.InputsMatchOne(Type::Number())) {
|
||||
// Math.log10(a:number) -> NumberLog10(a)
|
||||
Node* value = graph()->NewNode(simplified()->NumberLog10(), r.left());
|
||||
return Replace(value);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.28 Math.round ( x )
|
||||
Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
@ -341,6 +363,12 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
|
||||
case kMathLog1p:
|
||||
reduction = ReduceMathLog1p(node);
|
||||
break;
|
||||
case kMathLog2:
|
||||
reduction = ReduceMathLog2(node);
|
||||
break;
|
||||
case kMathLog10:
|
||||
reduction = ReduceMathLog10(node);
|
||||
break;
|
||||
case kMathMax:
|
||||
reduction = ReduceMathMax(node);
|
||||
break;
|
||||
|
@ -38,6 +38,8 @@ class JSBuiltinReducer final : public AdvancedReducer {
|
||||
Reduction ReduceMathImul(Node* node);
|
||||
Reduction ReduceMathLog(Node* node);
|
||||
Reduction ReduceMathLog1p(Node* node);
|
||||
Reduction ReduceMathLog2(Node* node);
|
||||
Reduction ReduceMathLog10(Node* node);
|
||||
Reduction ReduceMathMax(Node* node);
|
||||
Reduction ReduceMathMin(Node* node);
|
||||
Reduction ReduceMathRound(Node* node);
|
||||
|
@ -412,6 +412,16 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
|
||||
if (m.HasValue()) return ReplaceFloat64(base::ieee754::log1p(m.Value()));
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kFloat64Log2: {
|
||||
Float64Matcher m(node->InputAt(0));
|
||||
if (m.HasValue()) return ReplaceFloat64(base::ieee754::log2(m.Value()));
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kFloat64Log10: {
|
||||
Float64Matcher m(node->InputAt(0));
|
||||
if (m.HasValue()) return ReplaceFloat64(base::ieee754::log10(m.Value()));
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kChangeFloat32ToFloat64: {
|
||||
Float32Matcher m(node->InputAt(0));
|
||||
if (m.HasValue()) return ReplaceFloat64(m.Value());
|
||||
|
@ -159,6 +159,8 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
|
||||
V(Float64Atan2, Operator::kNoProperties, 2, 0, 1) \
|
||||
V(Float64Log, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Log1p, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Log2, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Log10, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Add, Operator::kCommutative, 2, 0, 1) \
|
||||
V(Float64Sub, Operator::kNoProperties, 2, 0, 1) \
|
||||
V(Float64SubPreserveNan, Operator::kNoProperties, 2, 0, 1) \
|
||||
|
@ -375,6 +375,8 @@ class MachineOperatorBuilder final : public ZoneObject {
|
||||
// Floating point logarithm (double-precision).
|
||||
const Operator* Float64Log();
|
||||
const Operator* Float64Log1p();
|
||||
const Operator* Float64Log2();
|
||||
const Operator* Float64Log10();
|
||||
|
||||
// Floating point bit representation.
|
||||
const Operator* Float64ExtractLowWord32();
|
||||
|
@ -753,6 +753,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
case kIeee754Float64Log2:
|
||||
ASSEMBLE_IEEE754_UNOP(log2);
|
||||
break;
|
||||
case kIeee754Float64Log10:
|
||||
ASSEMBLE_IEEE754_UNOP(log10);
|
||||
break;
|
||||
case kMipsAdd:
|
||||
__ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
|
||||
break;
|
||||
|
@ -762,6 +762,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
case kIeee754Float64Log2:
|
||||
ASSEMBLE_IEEE754_UNOP(log2);
|
||||
break;
|
||||
case kIeee754Float64Log10:
|
||||
ASSEMBLE_IEEE754_UNOP(log10);
|
||||
break;
|
||||
case kMips64Add:
|
||||
__ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
|
||||
break;
|
||||
|
@ -205,6 +205,8 @@
|
||||
V(NumberAtan2) \
|
||||
V(NumberLog) \
|
||||
V(NumberLog1p) \
|
||||
V(NumberLog2) \
|
||||
V(NumberLog10) \
|
||||
V(NumberRound) \
|
||||
V(NumberSqrt) \
|
||||
V(NumberTrunc) \
|
||||
@ -371,6 +373,8 @@
|
||||
V(Float64Atan2) \
|
||||
V(Float64Log) \
|
||||
V(Float64Log1p) \
|
||||
V(Float64Log2) \
|
||||
V(Float64Log10) \
|
||||
V(Float64Sqrt) \
|
||||
V(Float64RoundDown) \
|
||||
V(Float32RoundUp) \
|
||||
|
@ -466,6 +466,8 @@ class RawMachineAssembler {
|
||||
}
|
||||
Node* Float64Log(Node* a) { return AddNode(machine()->Float64Log(), a); }
|
||||
Node* Float64Log1p(Node* a) { return AddNode(machine()->Float64Log1p(), a); }
|
||||
Node* Float64Log2(Node* a) { return AddNode(machine()->Float64Log2(), a); }
|
||||
Node* Float64Log10(Node* a) { return AddNode(machine()->Float64Log10(), a); }
|
||||
Node* Float64Sqrt(Node* a) { return AddNode(machine()->Float64Sqrt(), a); }
|
||||
Node* Float64Equal(Node* a, Node* b) {
|
||||
return AddNode(machine()->Float64Equal(), a, b);
|
||||
|
@ -677,6 +677,10 @@ const Operator* RepresentationChanger::Float64OperatorFor(
|
||||
return machine()->Float64Log();
|
||||
case IrOpcode::kNumberLog1p:
|
||||
return machine()->Float64Log1p();
|
||||
case IrOpcode::kNumberLog2:
|
||||
return machine()->Float64Log2();
|
||||
case IrOpcode::kNumberLog10:
|
||||
return machine()->Float64Log10();
|
||||
case IrOpcode::kNumberSqrt:
|
||||
return machine()->Float64Sqrt();
|
||||
case IrOpcode::kNumberSilenceNaN:
|
||||
|
@ -1443,7 +1443,9 @@ class RepresentationSelector {
|
||||
}
|
||||
case IrOpcode::kNumberAtan:
|
||||
case IrOpcode::kNumberLog:
|
||||
case IrOpcode::kNumberLog1p: {
|
||||
case IrOpcode::kNumberLog1p:
|
||||
case IrOpcode::kNumberLog2:
|
||||
case IrOpcode::kNumberLog10: {
|
||||
VisitUnop(node, UseInfo::TruncatingFloat64(),
|
||||
MachineRepresentation::kFloat64);
|
||||
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
|
||||
|
@ -256,6 +256,8 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
|
||||
V(NumberAtan2, Operator::kNoProperties, 2) \
|
||||
V(NumberLog, Operator::kNoProperties, 1) \
|
||||
V(NumberLog1p, Operator::kNoProperties, 1) \
|
||||
V(NumberLog2, Operator::kNoProperties, 1) \
|
||||
V(NumberLog10, Operator::kNoProperties, 1) \
|
||||
V(NumberRound, Operator::kNoProperties, 1) \
|
||||
V(NumberSqrt, Operator::kNoProperties, 1) \
|
||||
V(NumberTrunc, Operator::kNoProperties, 1) \
|
||||
|
@ -183,6 +183,8 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
|
||||
const Operator* NumberAtan2();
|
||||
const Operator* NumberLog();
|
||||
const Operator* NumberLog1p();
|
||||
const Operator* NumberLog2();
|
||||
const Operator* NumberLog10();
|
||||
const Operator* NumberRound();
|
||||
const Operator* NumberSqrt();
|
||||
const Operator* NumberTrunc();
|
||||
|
@ -1804,6 +1804,10 @@ Type* Typer::Visitor::TypeNumberLog(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberLog1p(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberLog2(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberLog10(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberRound(Node* node) {
|
||||
return TypeUnaryOp(node, NumberRound);
|
||||
}
|
||||
@ -2559,6 +2563,10 @@ Type* Typer::Visitor::TypeFloat64Log(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Log1p(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Log2(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Log10(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Sqrt(Node* node) { return Type::Number(); }
|
||||
|
||||
|
||||
|
@ -755,6 +755,8 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kNumberAtan:
|
||||
case IrOpcode::kNumberLog:
|
||||
case IrOpcode::kNumberLog1p:
|
||||
case IrOpcode::kNumberLog2:
|
||||
case IrOpcode::kNumberLog10:
|
||||
case IrOpcode::kNumberRound:
|
||||
case IrOpcode::kNumberSqrt:
|
||||
case IrOpcode::kNumberTrunc:
|
||||
@ -1070,6 +1072,8 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kFloat64Atan2:
|
||||
case IrOpcode::kFloat64Log:
|
||||
case IrOpcode::kFloat64Log1p:
|
||||
case IrOpcode::kFloat64Log2:
|
||||
case IrOpcode::kFloat64Log10:
|
||||
case IrOpcode::kFloat64Sqrt:
|
||||
case IrOpcode::kFloat32RoundDown:
|
||||
case IrOpcode::kFloat64RoundDown:
|
||||
|
@ -879,6 +879,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
case kIeee754Float64Log2:
|
||||
ASSEMBLE_IEEE754_UNOP(log2);
|
||||
break;
|
||||
case kIeee754Float64Log10:
|
||||
ASSEMBLE_IEEE754_UNOP(log10);
|
||||
break;
|
||||
case kX64Add32:
|
||||
ASSEMBLE_BINOP(addl);
|
||||
break;
|
||||
|
@ -75,6 +75,10 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
|
||||
"base::ieee754::log");
|
||||
Add(ExternalReference::ieee754_log1p_function(isolate).address(),
|
||||
"base::ieee754::log1p");
|
||||
Add(ExternalReference::ieee754_log2_function(isolate).address(),
|
||||
"base::ieee754::log2");
|
||||
Add(ExternalReference::ieee754_log10_function(isolate).address(),
|
||||
"base::ieee754::log10");
|
||||
Add(ExternalReference::store_buffer_top(isolate).address(),
|
||||
"store_buffer_top");
|
||||
Add(ExternalReference::address_of_the_hole_nan().address(), "the_hole_nan");
|
||||
|
@ -6589,6 +6589,8 @@ class Script: public Struct {
|
||||
V(Math, abs, MathAbs) \
|
||||
V(Math, log, MathLog) \
|
||||
V(Math, log1p, MathLog1p) \
|
||||
V(Math, log2, MathLog2) \
|
||||
V(Math, log10, MathLog10) \
|
||||
V(Math, exp, MathExp) \
|
||||
V(Math, sqrt, MathSqrt) \
|
||||
V(Math, pow, MathPow) \
|
||||
|
183
src/third_party/fdlibm/fdlibm.js
vendored
183
src/third_party/fdlibm/fdlibm.js
vendored
@ -757,187 +757,6 @@ function MathTanh(x) {
|
||||
return (x >= 0) ? z : -z;
|
||||
}
|
||||
|
||||
// ES6 draft 09-27-13, section 20.2.2.21.
|
||||
// Return the base 10 logarithm of x
|
||||
//
|
||||
// Method :
|
||||
// Let log10_2hi = leading 40 bits of log10(2) and
|
||||
// log10_2lo = log10(2) - log10_2hi,
|
||||
// ivln10 = 1/log(10) rounded.
|
||||
// Then
|
||||
// n = ilogb(x),
|
||||
// if(n<0) n = n+1;
|
||||
// x = scalbn(x,-n);
|
||||
// log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
|
||||
//
|
||||
// Note 1:
|
||||
// To guarantee log10(10**n)=n, where 10**n is normal, the rounding
|
||||
// mode must set to Round-to-Nearest.
|
||||
// Note 2:
|
||||
// [1/log(10)] rounded to 53 bits has error .198 ulps;
|
||||
// log10 is monotonic at all binary break points.
|
||||
//
|
||||
// Special cases:
|
||||
// log10(x) is NaN if x < 0;
|
||||
// log10(+INF) is +INF; log10(0) is -INF;
|
||||
// log10(NaN) is that NaN;
|
||||
// log10(10**N) = N for N=0,1,...,22.
|
||||
//
|
||||
|
||||
define IVLN10 = 4.34294481903251816668e-01;
|
||||
define LOG10_2HI = 3.01029995663611771306e-01;
|
||||
define LOG10_2LO = 3.69423907715893078616e-13;
|
||||
|
||||
function MathLog10(x) {
|
||||
x = x * 1; // Convert to number.
|
||||
var hx = %_DoubleHi(x);
|
||||
var lx = %_DoubleLo(x);
|
||||
var k = 0;
|
||||
|
||||
if (hx < 0x00100000) {
|
||||
// x < 2^-1022
|
||||
// log10(+/- 0) = -Infinity.
|
||||
if (((hx & 0x7fffffff) | lx) === 0) return -INFINITY;
|
||||
// log10 of negative number is NaN.
|
||||
if (hx < 0) return NaN;
|
||||
// Subnormal number. Scale up x.
|
||||
k -= 54;
|
||||
x *= TWO54;
|
||||
hx = %_DoubleHi(x);
|
||||
lx = %_DoubleLo(x);
|
||||
}
|
||||
|
||||
// Infinity or NaN.
|
||||
if (hx >= 0x7ff00000) return x;
|
||||
|
||||
k += (hx >> 20) - 1023;
|
||||
var i = (k & 0x80000000) >>> 31;
|
||||
hx = (hx & 0x000fffff) | ((0x3ff - i) << 20);
|
||||
var y = k + i;
|
||||
x = %_ConstructDouble(hx, lx);
|
||||
|
||||
var z = y * LOG10_2LO + IVLN10 * %math_log(x);
|
||||
return z + y * LOG10_2HI;
|
||||
}
|
||||
|
||||
|
||||
// ES6 draft 09-27-13, section 20.2.2.22.
|
||||
// Return the base 2 logarithm of x
|
||||
//
|
||||
// fdlibm does not have an explicit log2 function, but fdlibm's pow
|
||||
// function does implement an accurate log2 function as part of the
|
||||
// pow implementation. This extracts the core parts of that as a
|
||||
// separate log2 function.
|
||||
|
||||
// Method:
|
||||
// Compute log2(x) in two pieces:
|
||||
// log2(x) = w1 + w2
|
||||
// where w1 has 53-24 = 29 bits of trailing zeroes.
|
||||
|
||||
define DP_H = 5.84962487220764160156e-01;
|
||||
define DP_L = 1.35003920212974897128e-08;
|
||||
|
||||
// Polynomial coefficients for (3/2)*(log2(x) - 2*s - 2/3*s^3)
|
||||
define LOG2_1 = 5.99999999999994648725e-01;
|
||||
define LOG2_2 = 4.28571428578550184252e-01;
|
||||
define LOG2_3 = 3.33333329818377432918e-01;
|
||||
define LOG2_4 = 2.72728123808534006489e-01;
|
||||
define LOG2_5 = 2.30660745775561754067e-01;
|
||||
define LOG2_6 = 2.06975017800338417784e-01;
|
||||
|
||||
// cp = 2/(3*ln(2)). Note that cp_h + cp_l is cp, but with more accuracy.
|
||||
define CP = 9.61796693925975554329e-01;
|
||||
define CP_H = 9.61796700954437255859e-01;
|
||||
define CP_L = -7.02846165095275826516e-09;
|
||||
// 2^53
|
||||
define TWO53 = 9007199254740992;
|
||||
|
||||
function MathLog2(x) {
|
||||
x = x * 1; // Convert to number.
|
||||
var ax = MathAbs(x);
|
||||
var hx = %_DoubleHi(x);
|
||||
var lx = %_DoubleLo(x);
|
||||
var ix = hx & 0x7fffffff;
|
||||
|
||||
// Handle special cases.
|
||||
// log2(+/- 0) = -Infinity
|
||||
if ((ix | lx) == 0) return -INFINITY;
|
||||
|
||||
// log(x) = NaN, if x < 0
|
||||
if (hx < 0) return NaN;
|
||||
|
||||
// log2(Infinity) = Infinity, log2(NaN) = NaN
|
||||
if (ix >= 0x7ff00000) return x;
|
||||
|
||||
var n = 0;
|
||||
|
||||
// Take care of subnormal number.
|
||||
if (ix < 0x00100000) {
|
||||
ax *= TWO53;
|
||||
n -= 53;
|
||||
ix = %_DoubleHi(ax);
|
||||
}
|
||||
|
||||
n += (ix >> 20) - 0x3ff;
|
||||
var j = ix & 0x000fffff;
|
||||
|
||||
// Determine interval.
|
||||
ix = j | 0x3ff00000; // normalize ix.
|
||||
|
||||
var bp = 1;
|
||||
var dp_h = 0;
|
||||
var dp_l = 0;
|
||||
if (j > 0x3988e) { // |x| > sqrt(3/2)
|
||||
if (j < 0xbb67a) { // |x| < sqrt(3)
|
||||
bp = 1.5;
|
||||
dp_h = DP_H;
|
||||
dp_l = DP_L;
|
||||
} else {
|
||||
n += 1;
|
||||
ix -= 0x00100000;
|
||||
}
|
||||
}
|
||||
|
||||
ax = %_ConstructDouble(ix, %_DoubleLo(ax));
|
||||
|
||||
// Compute ss = s_h + s_l = (x - 1)/(x+1) or (x - 1.5)/(x + 1.5)
|
||||
var u = ax - bp;
|
||||
var v = 1 / (ax + bp);
|
||||
var ss = u * v;
|
||||
var s_h = %_ConstructDouble(%_DoubleHi(ss), 0);
|
||||
|
||||
// t_h = ax + bp[k] High
|
||||
var t_h = %_ConstructDouble(%_DoubleHi(ax + bp), 0)
|
||||
var t_l = ax - (t_h - bp);
|
||||
var s_l = v * ((u - s_h * t_h) - s_h * t_l);
|
||||
|
||||
// Compute log2(ax)
|
||||
var s2 = ss * ss;
|
||||
var r = s2 * s2 * (LOG2_1 + s2 * (LOG2_2 + s2 * (LOG2_3 + s2 * (
|
||||
LOG2_4 + s2 * (LOG2_5 + s2 * LOG2_6)))));
|
||||
r += s_l * (s_h + ss);
|
||||
s2 = s_h * s_h;
|
||||
t_h = %_ConstructDouble(%_DoubleHi(3.0 + s2 + r), 0);
|
||||
t_l = r - ((t_h - 3.0) - s2);
|
||||
// u + v = ss * (1 + ...)
|
||||
u = s_h * t_h;
|
||||
v = s_l * t_h + t_l * ss;
|
||||
|
||||
// 2 / (3 * log(2)) * (ss + ...)
|
||||
var p_h = %_ConstructDouble(%_DoubleHi(u + v), 0);
|
||||
var p_l = v - (p_h - u);
|
||||
var z_h = CP_H * p_h;
|
||||
var z_l = CP_L * p_h + p_l * CP + dp_l;
|
||||
|
||||
// log2(ax) = (ss + ...) * 2 / (3 * log(2)) = n + dp_h + z_h + z_l
|
||||
var t = n;
|
||||
var t1 = %_ConstructDouble(%_DoubleHi(((z_h + z_l) + dp_h) + t), 0);
|
||||
var t2 = z_l - (((t1 - t) - dp_h) - z_h);
|
||||
|
||||
// t1 + t2 = log2(ax), sum up because we do not care about extra precision.
|
||||
return t1 + t2;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
utils.InstallFunctions(GlobalMath, DONT_ENUM, [
|
||||
@ -947,8 +766,6 @@ utils.InstallFunctions(GlobalMath, DONT_ENUM, [
|
||||
"sinh", MathSinh,
|
||||
"cosh", MathCosh,
|
||||
"tanh", MathTanh,
|
||||
"log10", MathLog10,
|
||||
"log2", MathLog2,
|
||||
"expm1", MathExpm1
|
||||
]);
|
||||
|
||||
|
@ -5546,6 +5546,35 @@ TEST(RunFloat64Log1p) {
|
||||
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ieee754::log1p(*i), m.Call(*i)); }
|
||||
}
|
||||
|
||||
TEST(RunFloat64Log2) {
|
||||
BufferedRawMachineAssemblerTester<double> m(MachineType::Float64());
|
||||
m.Return(m.Float64Log2(m.Parameter(0)));
|
||||
CHECK(std::isnan(m.Call(std::numeric_limits<double>::quiet_NaN())));
|
||||
CHECK(std::isnan(m.Call(std::numeric_limits<double>::signaling_NaN())));
|
||||
CHECK(std::isnan(m.Call(-std::numeric_limits<double>::infinity())));
|
||||
CHECK(std::isnan(m.Call(-1.0)));
|
||||
CHECK_DOUBLE_EQ(-std::numeric_limits<double>::infinity(), m.Call(-0.0));
|
||||
CHECK_DOUBLE_EQ(-std::numeric_limits<double>::infinity(), m.Call(0.0));
|
||||
CHECK_DOUBLE_EQ(0.0, m.Call(1.0));
|
||||
CHECK_DOUBLE_EQ(std::numeric_limits<double>::infinity(),
|
||||
m.Call(std::numeric_limits<double>::infinity()));
|
||||
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ieee754::log2(*i), m.Call(*i)); }
|
||||
}
|
||||
|
||||
TEST(RunFloat64Log10) {
|
||||
BufferedRawMachineAssemblerTester<double> m(MachineType::Float64());
|
||||
m.Return(m.Float64Log10(m.Parameter(0)));
|
||||
CHECK(std::isnan(m.Call(std::numeric_limits<double>::quiet_NaN())));
|
||||
CHECK(std::isnan(m.Call(std::numeric_limits<double>::signaling_NaN())));
|
||||
CHECK(std::isnan(m.Call(-std::numeric_limits<double>::infinity())));
|
||||
CHECK(std::isnan(m.Call(-1.0)));
|
||||
CHECK_DOUBLE_EQ(-std::numeric_limits<double>::infinity(), m.Call(-0.0));
|
||||
CHECK_DOUBLE_EQ(-std::numeric_limits<double>::infinity(), m.Call(0.0));
|
||||
CHECK_DOUBLE_EQ(std::numeric_limits<double>::infinity(),
|
||||
m.Call(std::numeric_limits<double>::infinity()));
|
||||
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ieee754::log10(*i), m.Call(*i)); }
|
||||
}
|
||||
|
||||
static double two_30 = 1 << 30; // 2^30 is a smi boundary.
|
||||
static double two_52 = two_30 * (1 << 22); // 2^52 is a precision boundary.
|
||||
static double kValues[] = {0.1,
|
||||
|
@ -91,6 +91,33 @@ TEST(Ieee754, Log1p) {
|
||||
EXPECT_EQ(0.8109302162163288, log1p(1.25));
|
||||
}
|
||||
|
||||
TEST(Ieee754, Log2) {
|
||||
EXPECT_THAT(log2(std::numeric_limits<double>::quiet_NaN()), IsNaN());
|
||||
EXPECT_THAT(log2(std::numeric_limits<double>::signaling_NaN()), IsNaN());
|
||||
EXPECT_THAT(log2(-std::numeric_limits<double>::infinity()), IsNaN());
|
||||
EXPECT_THAT(log2(-1.0), IsNaN());
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), log2(0.0));
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), log2(-0.0));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
||||
log2(std::numeric_limits<double>::infinity()));
|
||||
}
|
||||
|
||||
TEST(Ieee754, Log10) {
|
||||
EXPECT_THAT(log10(std::numeric_limits<double>::quiet_NaN()), IsNaN());
|
||||
EXPECT_THAT(log10(std::numeric_limits<double>::signaling_NaN()), IsNaN());
|
||||
EXPECT_THAT(log10(-std::numeric_limits<double>::infinity()), IsNaN());
|
||||
EXPECT_THAT(log10(-1.0), IsNaN());
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), log10(0.0));
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), log10(-0.0));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
||||
log10(std::numeric_limits<double>::infinity()));
|
||||
EXPECT_EQ(3.0, log10(1000.0));
|
||||
EXPECT_EQ(14.0, log10(100000000000000)); // log10(10 ^ 14)
|
||||
EXPECT_EQ(3.7389561269540406, log10(5482.2158));
|
||||
EXPECT_EQ(14.661551142893833, log10(458723662312872.125782332587));
|
||||
EXPECT_EQ(-0.9083828622192334, log10(0.12348583358871));
|
||||
}
|
||||
|
||||
} // namespace ieee754
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
@ -2317,6 +2317,8 @@ IS_UNOP_MATCHER(NumberFloor)
|
||||
IS_UNOP_MATCHER(NumberFround)
|
||||
IS_UNOP_MATCHER(NumberLog)
|
||||
IS_UNOP_MATCHER(NumberLog1p)
|
||||
IS_UNOP_MATCHER(NumberLog2)
|
||||
IS_UNOP_MATCHER(NumberLog10)
|
||||
IS_UNOP_MATCHER(NumberRound)
|
||||
IS_UNOP_MATCHER(NumberSqrt)
|
||||
IS_UNOP_MATCHER(NumberTrunc)
|
||||
|
@ -233,6 +233,8 @@ Matcher<Node*> IsNumberFloor(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberFround(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberLog(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberLog1p(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberLog2(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberLog10(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberRound(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberSqrt(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberTrunc(const Matcher<Node*>& value_matcher);
|
||||
|
Loading…
Reference in New Issue
Block a user