}
-void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
+void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
// Load the argument on the stack and call the stub.
- TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::TAGGED);
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
}
-void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
- // Load the argument on the stack and call the runtime function.
+void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::COS,
+ TranscendentalCacheStub::TAGGED);
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
- __ CallRuntime(Runtime::kMath_sqrt, 1);
+ __ CallStub(&stub);
+ context()->Plug(r0);
+}
+
+
+void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::TAN,
+ TranscendentalCacheStub::TAGGED);
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+ VisitForStackValue(args->at(0));
+ __ CallStub(&stub);
+ context()->Plug(r0);
+}
+
+
+void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub::TAGGED);
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+ VisitForStackValue(args->at(0));
+ __ CallStub(&stub);
context()->Plug(r0);
}
-void FullCodeGenerator::EmitMathFloor(CallRuntime* expr) {
+void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
// Load the argument on the stack and call the runtime function.
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
- __ CallRuntime(Runtime::kMath_floor, 1);
+ __ CallRuntime(Runtime::kMath_sqrt, 1);
context()->Plug(r0);
}
Handle<JSFunction> caller = current_info()->closure();
Handle<SharedFunctionInfo> target_shared(target->shared());
- // Always inline builtins marked for inlining.
- if (target->IsBuiltin()) {
- return target_shared->inline_builtin() ? 0 : kNotInlinable;
- }
-
// Do a quick check on source code length to avoid parsing large
// inlining candidates.
if (target_shared->SourceSize() >
}
// Target must be inlineable.
- if (!target_shared->IsInlineable()) {
+ if (!target->IsInlineable()) {
TraceInline(target, caller, "target not inlineable");
return kNotInlinable;
}
case kMathAbs:
case kMathSqrt:
case kMathLog:
+ case kMathSin:
+ case kMathCos:
+ case kMathTan:
if (expr->arguments()->length() == 1) {
HValue* argument = Pop();
Drop(1); // Receiver.
case kMathAbs:
case kMathSqrt:
case kMathLog:
+ case kMathSin:
+ case kMathCos:
+ case kMathTan:
if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
HValue* argument = Pop();
}
-void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
+void HOptimizedGraphBuilder::GenerateMathSin(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
- result->set_transcendental_type(TranscendentalCache::LOG);
+ result->set_transcendental_type(TranscendentalCache::SIN);
Drop(1);
return ast_context()->ReturnInstruction(result, call->id());
}
-void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
- ASSERT(call->arguments()->length() == 1);
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- HValue* value = Pop();
- HInstruction* result = New<HUnaryMathOperation>(value, kMathSqrt);
+void HOptimizedGraphBuilder::GenerateMathCos(CallRuntime* call) {
+ ASSERT_EQ(1, call->arguments()->length());
+ CHECK_ALIVE(VisitArgumentList(call->arguments()));
+ HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
+ result->set_transcendental_type(TranscendentalCache::COS);
+ Drop(1);
return ast_context()->ReturnInstruction(result, call->id());
}
-void HOptimizedGraphBuilder::GenerateMathFloor(CallRuntime* call) {
+void HOptimizedGraphBuilder::GenerateMathTan(CallRuntime* call) {
+ ASSERT_EQ(1, call->arguments()->length());
+ CHECK_ALIVE(VisitArgumentList(call->arguments()));
+ HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
+ result->set_transcendental_type(TranscendentalCache::TAN);
+ Drop(1);
+ return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
+void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
+ ASSERT_EQ(1, call->arguments()->length());
+ CHECK_ALIVE(VisitArgumentList(call->arguments()));
+ HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
+ result->set_transcendental_type(TranscendentalCache::LOG);
+ Drop(1);
+ return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
+void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
- HInstruction* result = New<HUnaryMathOperation>(value, kMathFloor);
+ HInstruction* result = New<HUnaryMathOperation>(value, kMathSqrt);
return ast_context()->ReturnInstruction(result, call->id());
}
}
-void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
+void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
// Load the argument on the stack and call the stub.
- TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::TAGGED);
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
}
-void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
- // Load the argument on the stack and call the runtime function.
+void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::COS,
+ TranscendentalCacheStub::TAGGED);
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
- __ CallRuntime(Runtime::kMath_sqrt, 1);
+ __ CallStub(&stub);
+ context()->Plug(eax);
+}
+
+
+void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::TAN,
+ TranscendentalCacheStub::TAGGED);
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+ VisitForStackValue(args->at(0));
+ __ CallStub(&stub);
+ context()->Plug(eax);
+}
+
+
+void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub::TAGGED);
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+ VisitForStackValue(args->at(0));
+ __ CallStub(&stub);
context()->Plug(eax);
}
-void FullCodeGenerator::EmitMathFloor(CallRuntime* expr) {
+void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
// Load the argument on the stack and call the runtime function.
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
- __ CallRuntime(Runtime::kMath_floor, 1);
+ __ CallRuntime(Runtime::kMath_sqrt, 1);
context()->Plug(eax);
}
// ECMA 262 - 15.8.2.7
function MathCos(x) {
- return MathCosImpl(x);
+ return %_MathCos(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.8
// ECMA 262 - 15.8.2.16
function MathSin(x) {
- return MathSinImpl(x);
+ return %_MathSin(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.17
// ECMA 262 - 15.8.2.18
function MathTan(x) {
- return MathSinImpl(x) / MathCosImpl(x);
+ return %_MathTan(TO_NUMBER_INLINE(x));
}
// Non-standard extension.
}
-var MathSinImpl = function(x) {
- InitTrigonometricFunctions();
- return MathSinImpl(x);
-}
-
-
-var MathCosImpl = function(x) {
- InitTrigonometricFunctions();
- return MathCosImpl(x);
-}
-
-
-function InitTrigonometricFunctions() {
- var samples = 2048; // Table size.
- var pi = 3.1415926535897932;
- var pi_half = pi / 2;
- var inverse_pi_half = 1 / pi_half;
- var two_pi = pi * 2;
- var interval = pi_half / samples;
- var inverse_interval = samples / pi_half;
- var table_sin = new global.Float64Array(samples + 2);
- var table_cos_interval = new global.Float64Array(samples + 2);
-
- %PopulateTrigonometricTable(table_sin, table_cos_interval, samples);
-
- // This implements the following algorithm.
- // 1) Multiplication takes care of to-number conversion.
- // 2) Reduce x to the first quadrant [0, pi/2].
- // Conveniently enough, in case of +/-Infinity, we get NaN.
- // 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant.
- // 4) Do a table lookup for the closest samples to the left and right of x.
- // 5) Find the derivatives at those sampling points by table lookup:
- // dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2].
- // 6) Use cubic spline interpolation to approximate sin(x).
- // 7) Negate the result if x was in the 3rd or 4th quadrant.
- // 8) Get rid of -0 by adding 0.
- MathSinImpl = function(x) {
- var multiple = %_MathFloor(x * inverse_pi_half);
- x = (multiple & 1) * pi_half +
- (1 - ((multiple & 1) << 1)) * (x - multiple * pi_half);
- var double_index = x * inverse_interval;
- var index = double_index | 0;
- var t1 = double_index - index;
- var t2 = 1 - t1;
- var y1 = table_sin[index];
- var y2 = table_sin[index + 1];
- var dy = y2 - y1;
- return (t2 * y1 + t1 * y2 +
- t1 * t2 * ((table_cos_interval[index] - dy) * t2 +
- (dy - table_cos_interval[index + 1]) * t1)) *
- (1 - (multiple & 2)) + 0;
- };
-
- MathCosImpl = function(x) {
- return MathSinImpl(x + pi_half);
- };
-
- %SetInlineBuiltinFlag(MathSinImpl);
- %SetInlineBuiltinFlag(MathCosImpl);
-}
-
-
// -------------------------------------------------------------------
function SetUpMath() {
"min", MathMin,
"imul", MathImul
));
-
- %SetInlineBuiltinFlag(MathSin);
- %SetInlineBuiltinFlag(MathCos);
- %SetInlineBuiltinFlag(MathTan);
}
SetUpMath();
}
-void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
+void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
// Load the argument on the stack and call the stub.
- TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::TAGGED);
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
}
-void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
- // Load the argument on the stack and call the runtime function.
+void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::COS,
+ TranscendentalCacheStub::TAGGED);
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
- __ CallRuntime(Runtime::kMath_sqrt, 1);
+ __ mov(a0, result_register()); // Stub requires parameter in a0 and on tos.
+ __ CallStub(&stub);
context()->Plug(v0);
}
-void FullCodeGenerator::EmitMathFloor(CallRuntime* expr) {
+void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::TAN,
+ TranscendentalCacheStub::TAGGED);
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+ VisitForStackValue(args->at(0));
+ __ mov(a0, result_register()); // Stub requires parameter in a0 and on tos.
+ __ CallStub(&stub);
+ context()->Plug(v0);
+}
+
+
+void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub::TAGGED);
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+ VisitForStackValue(args->at(0));
+ __ mov(a0, result_register()); // Stub requires parameter in a0 and on tos.
+ __ CallStub(&stub);
+ context()->Plug(v0);
+}
+
+
+void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
// Load the argument on the stack and call the runtime function.
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
- __ CallRuntime(Runtime::kMath_floor, 1);
+ __ CallRuntime(Runtime::kMath_sqrt, 1);
context()->Plug(v0);
}
BOOL_GETTER(SharedFunctionInfo, compiler_hints, is_extended_mode,
kExtendedModeFunction)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
-BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, inline_builtin,
- kInlineBuiltin)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
name_should_print_as_anonymous,
kNameShouldPrintAsAnonymous)
void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) {
- ASSERT(value->kind() != Code::OPTIMIZED_FUNCTION);
WRITE_FIELD(this, kCodeOffset, value);
CONDITIONAL_WRITE_BARRIER(value->GetHeap(), this, kCodeOffset, value, mode);
}
}
+bool JSFunction::IsInlineable() {
+ if (IsBuiltin()) return false;
+ SharedFunctionInfo* shared_info = shared();
+ // Check that the function has a script associated with it.
+ if (!shared_info->script()->IsScript()) return false;
+ if (shared_info->optimization_disabled()) return false;
+ Code* code = shared_info->code();
+ if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
+ // If we never ran this (unlikely) then lets try to optimize it.
+ if (code->kind() != Code::FUNCTION) return true;
+ return code->optimizable();
+}
+
+
void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
if (object->IsGlobalObject()) return;
}
-bool SharedFunctionInfo::IsInlineable() {
- // Check that the function has a script associated with it.
- if (!script()->IsScript()) return false;
- if (optimization_disabled()) return false;
- // If we never ran this (unlikely) then lets try to optimize it.
- if (code()->kind() != Code::FUNCTION) return true;
- return code()->optimizable();
-}
-
-
int SharedFunctionInfo::SourceSize() {
return end_position() - start_position();
}
// global object.
DECL_BOOLEAN_ACCESSORS(native)
- // Indicate that this builtin needs to be inlined in crankshaft.
- DECL_BOOLEAN_ACCESSORS(inline_builtin)
-
// Indicates that the function was created by the Function function.
// Though it's anonymous, toString should treat it as if it had the name
// "anonymous". We don't set the name itself so that the system does not
set_dont_optimize(reason != kNoReason);
}
- // Check whether or not this function is inlineable.
- bool IsInlineable();
-
// Source size of this function.
int SourceSize();
kUsesArguments,
kHasDuplicateParameters,
kNative,
- kInlineBuiltin,
kBoundFunction,
kIsAnonymous,
kNameShouldPrintAsAnonymous,
// Tells whether or not the function is on the concurrent recompilation queue.
inline bool IsInRecompileQueue();
+ // Check whether or not this function is inlineable.
+ bool IsInlineable();
+
// [literals_or_bindings]: Fixed array holding either
// the materialized literals or the bindings of a bound function.
//
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInlineBuiltinFlag) {
- SealHandleScope shs(isolate);
- RUNTIME_ASSERT(args.length() == 1);
-
- Handle<Object> object = args.at<Object>(0);
-
- if (object->IsJSFunction()) {
- JSFunction* func = JSFunction::cast(*object);
- func->shared()->set_inline_builtin(true);
- }
- return isolate->heap()->undefined_value();
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 5);
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_PopulateTrigonometricTable) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 3);
- CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sin_table, 0);
- CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, cos_table, 1);
- CONVERT_SMI_ARG_CHECKED(samples, 2);
- RUNTIME_ASSERT(sin_table->type() == kExternalDoubleArray);
- RUNTIME_ASSERT(cos_table->type() == kExternalDoubleArray);
- double* sin_buffer = reinterpret_cast<double*>(
- JSArrayBuffer::cast(sin_table->buffer())->backing_store());
- double* cos_buffer = reinterpret_cast<double*>(
- JSArrayBuffer::cast(cos_table->buffer())->backing_store());
-
- static const double pi_half = 3.1415926535897932 / 2;
- double interval = pi_half / samples;
- for (int i = 0; i < samples + 1; i++) {
- double sample = sin(i * interval);
- sin_buffer[i] = sample;
- cos_buffer[samples - i] = sample * interval;
- }
-
- // Fill this to catch out of bound accesses when calculating Math.sin(pi/2).
- sin_buffer[samples + 1] = sin(pi_half + interval);
- cos_buffer[samples + 1] = cos(pi_half + interval) * interval;
-
- return isolate->heap()->undefined_value();
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
SealHandleScope shs(isolate);
ASSERT(args.length() == 2);
F(AllocateInOldPointerSpace, 1, 1) \
F(AllocateInOldDataSpace, 1, 1) \
F(SetNativeFlag, 1, 1) \
- F(SetInlineBuiltinFlag, 1, 1) \
F(StoreArrayLiteralElement, 5, 1) \
F(DebugCallbackSupportsStepping, 1, 1) \
F(DebugPrepareStepInIfStepping, 1, 1) \
F(Math_sin, 1, 1) \
F(Math_sqrt, 1, 1) \
F(Math_tan, 1, 1) \
- F(PopulateTrigonometricTable, 3, 1) \
\
/* Regular expressions */ \
F(RegExpCompile, 3, 1) \
F(IsSpecObject, 1, 1) \
F(IsStringWrapperSafeForDefaultValueOf, 1, 1) \
F(MathPow, 2, 1) \
+ F(MathSin, 1, 1) \
+ F(MathCos, 1, 1) \
+ F(MathTan, 1, 1) \
F(MathSqrt, 1, 1) \
F(MathLog, 1, 1) \
- F(MathFloor, 1, 1) \
F(IsRegExpEquivalent, 2, 1) \
F(HasCachedArrayIndex, 1, 1) \
F(GetCachedArrayIndex, 1, 1) \
}
-void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
+void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
// Load the argument on the stack and call the stub.
- TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::TAGGED);
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
}
-void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
- // Load the argument on the stack and call the runtime function.
+void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::COS,
+ TranscendentalCacheStub::TAGGED);
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
- __ CallRuntime(Runtime::kMath_sqrt, 1);
+ __ CallStub(&stub);
+ context()->Plug(rax);
+}
+
+
+void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::TAN,
+ TranscendentalCacheStub::TAGGED);
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+ VisitForStackValue(args->at(0));
+ __ CallStub(&stub);
+ context()->Plug(rax);
+}
+
+
+void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
+ // Load the argument on the stack and call the stub.
+ TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub::TAGGED);
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+ VisitForStackValue(args->at(0));
+ __ CallStub(&stub);
context()->Plug(rax);
}
-void FullCodeGenerator::EmitMathFloor(CallRuntime* expr) {
+void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
// Load the argument on the stack and call the runtime function.
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
- __ CallRuntime(Runtime::kMath_floor, 1);
+ __ CallRuntime(Runtime::kMath_sqrt, 1);
context()->Plug(rax);
}
// By accident, the slow case for sine and cosine were both sine at
// some point. This is a regression test for that issue.
-var x = Math.pow(2, 30);
+var x = Math.pow(2, 70);
assertTrue(Math.sin(x) != Math.cos(x));
// Ensure that sine and log are not the same.
x = 0.5;
assertTrue(Math.sin(x) != Math.log(x));
-
-// Test against approximation by series.
-var factorial = [1];
-var accuracy = 50;
-for (var i = 1; i < accuracy; i++) {
- factorial[i] = factorial[i-1] * i;
-}
-
-// We sum up in the reverse order for higher precision, as we expect the terms
-// to grow smaller for x reasonably close to 0.
-function precision_sum(array) {
- var result = 0;
- while (array.length > 0) {
- result += array.pop();
- }
- return result;
-}
-
-function sin(x) {
- var sign = 1;
- var x2 = x*x;
- var terms = [];
- for (var i = 1; i < accuracy; i += 2) {
- terms.push(sign * x / factorial[i]);
- x *= x2;
- sign *= -1;
- }
- return precision_sum(terms);
-}
-
-function cos(x) {
- var sign = -1;
- var x2 = x*x;
- x = x2;
- var terms = [1];
- for (var i = 2; i < accuracy; i += 2) {
- terms.push(sign * x / factorial[i]);
- x *= x2;
- sign *= -1;
- }
- return precision_sum(terms);
-}
-
-function abs_error(fun, ref, x) {
- return Math.abs(ref(x) - fun(x));
-}
-
-var test_inputs = [];
-for (var i = -10000; i < 10000; i += 177) test_inputs.push(i/1257);
-var epsilon = 0.000001;
-
-test_inputs.push(0);
-test_inputs.push(0 + epsilon);
-test_inputs.push(0 - epsilon);
-test_inputs.push(Math.PI/2);
-test_inputs.push(Math.PI/2 + epsilon);
-test_inputs.push(Math.PI/2 - epsilon);
-test_inputs.push(Math.PI);
-test_inputs.push(Math.PI + epsilon);
-test_inputs.push(Math.PI - epsilon);
-test_inputs.push(- 2*Math.PI);
-test_inputs.push(- 2*Math.PI + epsilon);
-test_inputs.push(- 2*Math.PI - epsilon);
-
-var squares = [];
-for (var i = 0; i < test_inputs.length; i++) {
- var x = test_inputs[i];
- var err_sin = abs_error(Math.sin, sin, x);
- var err_cos = abs_error(Math.cos, cos, x)
- assertTrue(err_sin < 1E-13);
- assertTrue(err_cos < 1E-13);
- squares.push(err_sin*err_sin + err_cos*err_cos);
-}
-
-// Sum squares up by adding them pairwise, to avoid losing precision.
-while (squares.length > 1) {
- var reduced = [];
- if (squares.length % 2 == 1) reduced.push(squares.pop());
- // Remaining number of elements is even.
- while(squares.length > 1) reduced.push(squares.pop() + squares.pop());
- squares = reduced;
-}
-
-var err_rms = Math.sqrt(squares[0] / test_inputs.length / 2);
-assertTrue(err_rms < 1E-14);
-
-assertEquals(-1, Math.cos({ valueOf: function() { return Math.PI; } }));
-assertEquals(0, Math.sin("0x00000"));
-assertTrue(isNaN(Math.sin(Infinity)));
-assertTrue(isNaN(Math.cos("-Infinity")));
-assertEquals("Infinity", String(Math.tan(Math.PI/2)));
-assertEquals("-Infinity", String(Math.tan(-Math.PI/2)));