1 // Copyright 2009 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 fast div and mod. 29 30 function divmod(div_func, mod_func, x, y) { 31 var div_answer = (div_func)(x); 32 assertEquals(x / y, div_answer, x + "/" + y); 33 var mod_answer = (mod_func)(x); 34 assertEquals(x % y, mod_answer, x + "%" + y); 35 var minus_div_answer = (div_func)(-x); 36 assertEquals(-x / y, minus_div_answer, "-" + x + "/" + y); 37 var minus_mod_answer = (mod_func)(-x); 38 assertEquals(-x % y, minus_mod_answer, "-" + x + "%" + y); 39 } 40 41 42 function run_tests_for(divisor) { 43 print("(function(left) { return left / " + divisor + "; })"); 44 var div_func = this.eval("(function(left) { return left / " + divisor + "; })"); 45 var mod_func = this.eval("(function(left) { return left % " + divisor + "; })"); 46 var exp; 47 // Strange number test. 48 divmod(div_func, mod_func, 0, divisor); 49 divmod(div_func, mod_func, 1 / 0, divisor); 50 // Floating point number test. 51 for (exp = -1024; exp <= 1024; exp += 8) { 52 divmod(div_func, mod_func, Math.pow(2, exp), divisor); 53 divmod(div_func, mod_func, 0.9999999 * Math.pow(2, exp), divisor); 54 divmod(div_func, mod_func, 1.0000001 * Math.pow(2, exp), divisor); 55 } 56 // Integer number test. 57 for (exp = 0; exp <= 32; exp++) { 58 divmod(div_func, mod_func, 1 << exp, divisor); 59 divmod(div_func, mod_func, (1 << exp) + 1, divisor); 60 divmod(div_func, mod_func, (1 << exp) - 1, divisor); 61 } 62 divmod(div_func, mod_func, Math.floor(0x1fffffff / 3), divisor); 63 divmod(div_func, mod_func, Math.floor(-0x20000000 / 3), divisor); 64 } 65 66 67 var divisors = [ 68 0, 69 1, 70 2, 71 3, 72 4, 73 5, 74 6, 75 7, 76 8, 77 9, 78 10, 79 0x1000000, 80 0x40000000, 81 12, 82 60, 83 100, 84 1000 * 60 * 60 * 24]; 85 86 for (var i = 0; i < divisors.length; i++) { 87 run_tests_for(divisors[i]); 88 } 89 90 // Test extreme corner cases of modulo. 91 92 // Computes the modulo by slow but lossless operations. 93 function compute_mod(dividend, divisor) { 94 // Return NaN if either operand is NaN, if divisor is 0 or 95 // dividend is an infinity. Return dividend if divisor is an infinity. 96 if (isNaN(dividend) || isNaN(divisor) || divisor == 0) { return NaN; } 97 var sign = 1; 98 if (dividend < 0) { dividend = -dividend; sign = -1; } 99 if (dividend == Infinity) { return NaN; } 100 if (divisor < 0) { divisor = -divisor; } 101 if (divisor == Infinity) { return sign * dividend; } 102 function rec_mod(a, b) { 103 // Subtracts maximal possible multiplum of b from a. 104 if (a >= b) { 105 a = rec_mod(a, 2 * b); 106 if (a >= b) { a -= b; } 107 } 108 return a; 109 } 110 return sign * rec_mod(dividend, divisor); 111 } 112 113 (function () { 114 var large_non_smi = 1234567891234.12245; 115 var small_non_smi = 43.2367243; 116 var repeating_decimal = 0.3; 117 var finite_decimal = 0.5; 118 var smi = 43; 119 var power_of_two = 64; 120 var min_normal = Number.MIN_VALUE * Math.pow(2, 52); 121 var max_denormal = Number.MIN_VALUE * (Math.pow(2, 52) - 1); 122 123 // All combinations of NaN, Infinity, normal, denormal and zero. 124 var example_numbers = [ 125 NaN, 126 0, 127 Number.MIN_VALUE, 128 3 * Number.MIN_VALUE, 129 max_denormal, 130 min_normal, 131 repeating_decimal, 132 finite_decimal, 133 smi, 134 power_of_two, 135 small_non_smi, 136 large_non_smi, 137 Number.MAX_VALUE, 138 Infinity 139 ]; 140 141 function doTest(a, b) { 142 var exp = compute_mod(a, b); 143 var act = a % b; 144 assertEquals(exp, act, a + " % " + b); 145 } 146 147 for (var i = 0; i < example_numbers.length; i++) { 148 for (var j = 0; j < example_numbers.length; j++) { 149 var a = example_numbers[i]; 150 var b = example_numbers[j]; 151 doTest(a,b); 152 doTest(-a,b); 153 doTest(a,-b); 154 doTest(-a,-b); 155 } 156 } 157 })(); 158 159 160 (function () { 161 // Edge cases 162 var zero = 0; 163 var minsmi32 = -0x40000000; 164 var minsmi64 = -0x80000000; 165 var somenum = 3532; 166 assertEquals(-0, zero / -1, "0 / -1"); 167 assertEquals(1, minsmi32 / -0x40000000, "minsmi/minsmi-32"); 168 assertEquals(1, minsmi64 / -0x80000000, "minsmi/minsmi-64"); 169 assertEquals(somenum, somenum % -0x40000000, "%minsmi-32"); 170 assertEquals(somenum, somenum % -0x80000000, "%minsmi-64"); 171 })(); 172 173 174 // Side-effect-free expressions containing bit operations use 175 // an optimized compiler with int32 values. Ensure that modulus 176 // produces negative zeros correctly. 177 function negative_zero_modulus_test() { 178 var x = 4; 179 var y = -4; 180 x = x + x - x; 181 y = y + y - y; 182 var z = (y | y | y | y) % x; 183 assertEquals(-1 / 0, 1 / z); 184 z = (x | x | x | x) % x; 185 assertEquals(1 / 0, 1 / z); 186 z = (y | y | y | y) % y; 187 assertEquals(-1 / 0, 1 / z); 188 z = (x | x | x | x) % y; 189 assertEquals(1 / 0, 1 / z); 190 } 191 192 negative_zero_modulus_test(); 193