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 32 assertEquals("-Infinity", String(1/Math.sin(-0))); 33 assertEquals(1, Math.cos(-0)); 34 assertEquals("-Infinity", String(1/Math.tan(-0))); 35 36 // Assert that minus zero does not cause deopt. 37 function no_deopt_on_minus_zero(x) { 38 return Math.sin(x) + Math.cos(x) + Math.tan(x); 39 } 40 41 no_deopt_on_minus_zero(1); 42 no_deopt_on_minus_zero(1); 43 %OptimizeFunctionOnNextCall(no_deopt_on_minus_zero); 44 no_deopt_on_minus_zero(-0); 45 assertOptimized(no_deopt_on_minus_zero); 46 47 48 function sinTest() { 49 assertEquals(0, Math.sin(0)); 50 assertEquals(1, Math.sin(Math.PI / 2)); 51 } 52 53 function cosTest() { 54 assertEquals(1, Math.cos(0)); 55 assertEquals(-1, Math.cos(Math.PI)); 56 } 57 58 sinTest(); 59 cosTest(); 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. 63 var x = Math.pow(2, 30); 64 assertTrue(Math.sin(x) != Math.cos(x)); 65 66 // Ensure that sine and log are not the same. 67 x = 0.5; 68 assertTrue(Math.sin(x) != Math.log(x)); 69 70 // Test against approximation by series. 71 var factorial = [1]; 72 var accuracy = 50; 73 for (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. 79 function precision_sum(array) { 80 var result = 0; 81 while (array.length > 0) { 82 result += array.pop(); 83 } 84 return result; 85 } 86 87 function 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 99 function 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 112 function abs_error(fun, ref, x) { 113 return Math.abs(ref(x) - fun(x)); 114 } 115 116 var test_inputs = []; 117 for (var i = -10000; i < 10000; i += 177) test_inputs.push(i/1257); 118 var epsilon = 0.0000001; 119 120 test_inputs.push(0); 121 test_inputs.push(0 + epsilon); 122 test_inputs.push(0 - epsilon); 123 test_inputs.push(Math.PI/2); 124 test_inputs.push(Math.PI/2 + epsilon); 125 test_inputs.push(Math.PI/2 - epsilon); 126 test_inputs.push(Math.PI); 127 test_inputs.push(Math.PI + epsilon); 128 test_inputs.push(Math.PI - epsilon); 129 test_inputs.push(- 2*Math.PI); 130 test_inputs.push(- 2*Math.PI + epsilon); 131 test_inputs.push(- 2*Math.PI - epsilon); 132 133 var squares = []; 134 for (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. 144 while (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 152 var err_rms = Math.sqrt(squares[0] / test_inputs.length / 2); 153 assertEqualsDelta(0, err_rms, 1E-14); 154 155 assertEquals(-1, Math.cos({ valueOf: function() { return Math.PI; } })); 156 assertEquals(0, Math.sin("0x00000")); 157 assertEquals(1, Math.cos("0x00000")); 158 assertTrue(isNaN(Math.sin(Infinity))); 159 assertTrue(isNaN(Math.cos("-Infinity"))); 160 assertEquals("Infinity", String(Math.tan(Math.PI/2))); 161 assertEquals("-Infinity", String(Math.tan(-Math.PI/2))); 162 assertEquals("-Infinity", String(1/Math.sin("-0"))); 163 164 // Assert that the remainder after division by pi is reasonably precise. 165 function assertError(expected, x, epsilon) { 166 assertTrue(Math.abs(x - expected) < epsilon); 167 } 168 169 assertEqualsDelta(0.9367521275331447, Math.cos(1e06), 1e-15); 170 assertEqualsDelta(0.8731196226768560, Math.cos(1e10), 1e-08); 171 assertEqualsDelta(0.9367521275331447, Math.cos(-1e06), 1e-15); 172 assertEqualsDelta(0.8731196226768560, Math.cos(-1e10), 1e-08); 173 assertEqualsDelta(-0.3499935021712929, Math.sin(1e06), 1e-15); 174 assertEqualsDelta(-0.4875060250875106, Math.sin(1e10), 1e-08); 175 assertEqualsDelta(0.3499935021712929, Math.sin(-1e06), 1e-15); 176 assertEqualsDelta(0.4875060250875106, Math.sin(-1e10), 1e-08); 177 assertEqualsDelta(0.7796880066069787, Math.sin(1e16), 1e-05); 178 assertEqualsDelta(-0.6261681981330861, Math.cos(1e16), 1e-05); 179 180 // Assert that remainder calculation terminates. 181 for (var i = -1024; i < 1024; i++) { 182 assertFalse(isNaN(Math.sin(Math.pow(2, i)))); 183 } 184 185 assertFalse(isNaN(Math.cos(1.57079632679489700))); 186 assertFalse(isNaN(Math.cos(-1e-100))); 187 assertFalse(isNaN(Math.cos(-1e-323))); 188