1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// Test Math.sin and Math.cos. 29 30// Flags: --allow-natives-syntax 31 32assertEquals("-Infinity", String(1/Math.sin(-0))); 33assertEquals(1, Math.cos(-0)); 34assertEquals("-Infinity", String(1/Math.tan(-0))); 35 36// Assert that minus zero does not cause deopt. 37function no_deopt_on_minus_zero(x) { 38 return Math.sin(x) + Math.cos(x) + Math.tan(x); 39} 40 41no_deopt_on_minus_zero(1); 42no_deopt_on_minus_zero(1); 43%OptimizeFunctionOnNextCall(no_deopt_on_minus_zero); 44no_deopt_on_minus_zero(-0); 45assertOptimized(no_deopt_on_minus_zero); 46 47 48function sinTest() { 49 assertEquals(0, Math.sin(0)); 50 assertEquals(1, Math.sin(Math.PI / 2)); 51} 52 53function cosTest() { 54 assertEquals(1, Math.cos(0)); 55 assertEquals(-1, Math.cos(Math.PI)); 56} 57 58sinTest(); 59cosTest(); 60 61// By accident, the slow case for sine and cosine were both sine at 62// some point. This is a regression test for that issue. 63var x = Math.pow(2, 30); 64assertTrue(Math.sin(x) != Math.cos(x)); 65 66// Ensure that sine and log are not the same. 67x = 0.5; 68assertTrue(Math.sin(x) != Math.log(x)); 69 70// Test against approximation by series. 71var factorial = [1]; 72var accuracy = 50; 73for (var i = 1; i < accuracy; i++) { 74 factorial[i] = factorial[i-1] * i; 75} 76 77// We sum up in the reverse order for higher precision, as we expect the terms 78// to grow smaller for x reasonably close to 0. 79function precision_sum(array) { 80 var result = 0; 81 while (array.length > 0) { 82 result += array.pop(); 83 } 84 return result; 85} 86 87function sin(x) { 88 var sign = 1; 89 var x2 = x*x; 90 var terms = []; 91 for (var i = 1; i < accuracy; i += 2) { 92 terms.push(sign * x / factorial[i]); 93 x *= x2; 94 sign *= -1; 95 } 96 return precision_sum(terms); 97} 98 99function cos(x) { 100 var sign = -1; 101 var x2 = x*x; 102 x = x2; 103 var terms = [1]; 104 for (var i = 2; i < accuracy; i += 2) { 105 terms.push(sign * x / factorial[i]); 106 x *= x2; 107 sign *= -1; 108 } 109 return precision_sum(terms); 110} 111 112function abs_error(fun, ref, x) { 113 return Math.abs(ref(x) - fun(x)); 114} 115 116var test_inputs = []; 117for (var i = -10000; i < 10000; i += 177) test_inputs.push(i/1257); 118var epsilon = 0.0000001; 119 120test_inputs.push(0); 121test_inputs.push(0 + epsilon); 122test_inputs.push(0 - epsilon); 123test_inputs.push(Math.PI/2); 124test_inputs.push(Math.PI/2 + epsilon); 125test_inputs.push(Math.PI/2 - epsilon); 126test_inputs.push(Math.PI); 127test_inputs.push(Math.PI + epsilon); 128test_inputs.push(Math.PI - epsilon); 129test_inputs.push(- 2*Math.PI); 130test_inputs.push(- 2*Math.PI + epsilon); 131test_inputs.push(- 2*Math.PI - epsilon); 132 133var squares = []; 134for (var i = 0; i < test_inputs.length; i++) { 135 var x = test_inputs[i]; 136 var err_sin = abs_error(Math.sin, sin, x); 137 var err_cos = abs_error(Math.cos, cos, x) 138 assertEqualsDelta(0, err_sin, 1E-13); 139 assertEqualsDelta(0, err_cos, 1E-13); 140 squares.push(err_sin*err_sin + err_cos*err_cos); 141} 142 143// Sum squares up by adding them pairwise, to avoid losing precision. 144while (squares.length > 1) { 145 var reduced = []; 146 if (squares.length % 2 == 1) reduced.push(squares.pop()); 147 // Remaining number of elements is even. 148 while(squares.length > 1) reduced.push(squares.pop() + squares.pop()); 149 squares = reduced; 150} 151 152var err_rms = Math.sqrt(squares[0] / test_inputs.length / 2); 153assertEqualsDelta(0, err_rms, 1E-14); 154 155assertEquals(-1, Math.cos({ valueOf: function() { return Math.PI; } })); 156assertEquals(0, Math.sin("0x00000")); 157assertEquals(1, Math.cos("0x00000")); 158assertTrue(isNaN(Math.sin(Infinity))); 159assertTrue(isNaN(Math.cos("-Infinity"))); 160assertEquals("Infinity", String(Math.tan(Math.PI/2))); 161assertEquals("-Infinity", String(Math.tan(-Math.PI/2))); 162assertEquals("-Infinity", String(1/Math.sin("-0"))); 163 164// Assert that the remainder after division by pi is reasonably precise. 165function assertError(expected, x, epsilon) { 166 assertTrue(Math.abs(x - expected) < epsilon); 167} 168 169assertEqualsDelta(0.9367521275331447, Math.cos(1e06), 1e-15); 170assertEqualsDelta(0.8731196226768560, Math.cos(1e10), 1e-08); 171assertEqualsDelta(0.9367521275331447, Math.cos(-1e06), 1e-15); 172assertEqualsDelta(0.8731196226768560, Math.cos(-1e10), 1e-08); 173assertEqualsDelta(-0.3499935021712929, Math.sin(1e06), 1e-15); 174assertEqualsDelta(-0.4875060250875106, Math.sin(1e10), 1e-08); 175assertEqualsDelta(0.3499935021712929, Math.sin(-1e06), 1e-15); 176assertEqualsDelta(0.4875060250875106, Math.sin(-1e10), 1e-08); 177assertEqualsDelta(0.7796880066069787, Math.sin(1e16), 1e-05); 178assertEqualsDelta(-0.6261681981330861, Math.cos(1e16), 1e-05); 179 180// Assert that remainder calculation terminates. 181for (var i = -1024; i < 1024; i++) { 182 assertFalse(isNaN(Math.sin(Math.pow(2, i)))); 183} 184 185assertFalse(isNaN(Math.cos(1.57079632679489700))); 186assertFalse(isNaN(Math.cos(-1e-100))); 187assertFalse(isNaN(Math.cos(-1e-323))); 188