1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 // This file is available under and governed by the GNU General Public 27 // License version 2 only, as published by the Free Software Foundation. 28 // However, the following notice accompanied the original version of this 29 // file: 30 // 31 // Copyright 2006-2008 the V8 project authors. All rights reserved. 32 33 package jdk.nashorn.internal.runtime.doubleconv.test; 34 35 import org.testng.annotations.Test; 36 37 import java.lang.reflect.Constructor; 38 import java.lang.reflect.Method; 39 40 import static org.testng.Assert.assertEquals; 41 import static org.testng.Assert.assertTrue; 42 43 /** 44 * Ieee class tests 45 * 46 * @test 47 * @run testng jdk.nashorn.internal.runtime.doubleconv.test.IeeeTest 48 */ 49 @SuppressWarnings({"unchecked", "javadoc"}) 50 public class IeeeDoubleTest { 51 52 static final Method asDiyFp; 53 static final Method asNormalizedDiyFp; 54 static final Method doubleToLong; 55 static final Method longToDouble; 56 static final Method isDenormal; 57 static final Method isSpecial; 58 static final Method isInfinite; 59 static final Method isNaN; 60 static final Method value; 61 static final Method sign; 62 static final Method nextDouble; 63 static final Method previousDouble; 64 static final Method normalizedBoundaries; 65 static final Method Infinity; 66 static final Method NaN; 67 static final Method f; 68 static final Method e; 69 static final Constructor<?> DiyFpCtor; 70 71 static { 72 try { 73 final Class<?> IeeeDouble = Class.forName("jdk.nashorn.internal.runtime.doubleconv.IeeeDouble"); 74 final Class DiyFp = Class.forName("jdk.nashorn.internal.runtime.doubleconv.DiyFp"); 75 asDiyFp = method(IeeeDouble, "asDiyFp", long.class); 76 asNormalizedDiyFp = method(IeeeDouble, "asNormalizedDiyFp", long.class); 77 doubleToLong = method(IeeeDouble, "doubleToLong", double.class); 78 longToDouble = method(IeeeDouble, "longToDouble", long.class); 79 isDenormal = method(IeeeDouble, "isDenormal", long.class); 80 isSpecial = method(IeeeDouble, "isSpecial", long.class); 81 isInfinite = method(IeeeDouble, "isInfinite", long.class); 82 isNaN = method(IeeeDouble, "isNaN", long.class); 83 value = method(IeeeDouble, "value", long.class); 84 sign = method(IeeeDouble, "sign", long.class); 85 nextDouble = method(IeeeDouble, "nextDouble", long.class); 86 previousDouble = method(IeeeDouble, "previousDouble", long.class); 87 Infinity = method(IeeeDouble, "Infinity"); 88 NaN = method(IeeeDouble, "NaN"); 89 normalizedBoundaries = method(IeeeDouble, "normalizedBoundaries", long.class, DiyFp, DiyFp); 90 DiyFpCtor = DiyFp.getDeclaredConstructor(); 91 DiyFpCtor.setAccessible(true); 92 f = method(DiyFp, "f"); 93 e = method(DiyFp, "e"); 94 } catch (final Exception e) { 95 throw new RuntimeException(e); 96 } 97 } 98 99 private static Method method(final Class<?> clazz, final String name, final Class<?>... params) throws NoSuchMethodException { 100 final Method m = clazz.getDeclaredMethod(name, params); 101 m.setAccessible(true); 102 return m; 103 } 104 105 @Test 106 public void testUint64Conversions() throws Exception { 107 // Start by checking the byte-order. 108 final long ordered = 0x0123456789ABCDEFL; 109 assertEquals(3512700564088504e-318, value.invoke(null, ordered)); 110 111 final long min_double64 = 0x0000000000000001L; 112 assertEquals(5e-324, value.invoke(null, min_double64)); 113 114 final long max_double64 = 0x7fefffffffffffffL; 115 assertEquals(1.7976931348623157e308, value.invoke(null, max_double64)); 116 } 117 118 119 @Test 120 public void testDoubleAsDiyFp() throws Exception { 121 final long ordered = 0x0123456789ABCDEFL; 122 Object diy_fp = asDiyFp.invoke(null, ordered); 123 assertEquals(0x12 - 0x3FF - 52, e.invoke(diy_fp)); 124 // The 52 mantissa bits, plus the implicit 1 in bit 52 as a UINT64. 125 assertTrue(0x0013456789ABCDEFL == (long) f.invoke(diy_fp)); 126 127 final long min_double64 = 0x0000000000000001L; 128 diy_fp = asDiyFp.invoke(null, min_double64); 129 assertEquals(-0x3FF - 52 + 1, e.invoke(diy_fp)); 130 // This is a denormal; so no hidden bit. 131 assertTrue(1L == (long) f.invoke(diy_fp)); 132 133 final long max_double64 = 0x7fefffffffffffffL; 134 diy_fp = asDiyFp.invoke(null, max_double64); 135 assertEquals(0x7FE - 0x3FF - 52, e.invoke(diy_fp)); 136 assertTrue(0x001fffffffffffffL == (long) f.invoke(diy_fp)); 137 } 138 139 140 @Test 141 public void testAsNormalizedDiyFp() throws Exception { 142 final long ordered = 0x0123456789ABCDEFL; 143 Object diy_fp = asNormalizedDiyFp.invoke(null, ordered); 144 assertEquals(0x12 - 0x3FF - 52 - 11, (int) e.invoke(diy_fp)); 145 assertTrue((0x0013456789ABCDEFL << 11) == (long) f.invoke(diy_fp)); 146 147 final long min_double64 = 0x0000000000000001L; 148 diy_fp = asNormalizedDiyFp.invoke(null, min_double64); 149 assertEquals(-0x3FF - 52 + 1 - 63, e.invoke(diy_fp)); 150 // This is a denormal; so no hidden bit. 151 assertTrue(0x8000000000000000L == (long) f.invoke(diy_fp)); 152 153 final long max_double64 = 0x7fefffffffffffffL; 154 diy_fp = asNormalizedDiyFp.invoke(null, max_double64); 155 assertEquals(0x7FE - 0x3FF - 52 - 11, e.invoke(diy_fp)); 156 assertTrue((0x001fffffffffffffL << 11) == (long) f.invoke(diy_fp)); 157 } 158 159 160 @Test 161 public void testIsDenormal() throws Exception { 162 final long min_double64 = 0x0000000000000001L; 163 assertTrue((boolean) isDenormal.invoke(null, min_double64)); 164 long bits = 0x000FFFFFFFFFFFFFL; 165 assertTrue((boolean) isDenormal.invoke(null, bits)); 166 bits = 0x0010000000000000L; 167 assertTrue(!(boolean) isDenormal.invoke(null, bits)); 168 } 169 170 @Test 171 public void testIsSpecial() throws Exception { 172 assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 173 assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 174 assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, NaN.invoke(null)))); 175 final long bits = 0xFFF1234500000000L; 176 assertTrue((boolean) isSpecial.invoke(null, bits)); 177 // Denormals are not special: 178 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 5e-324))); 179 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -5e-324))); 180 // And some random numbers: 181 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 0.0))); 182 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -0.0))); 183 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1.0))); 184 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1.0))); 185 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1000000.0))); 186 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1000000.0))); 187 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1e23))); 188 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1e23))); 189 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1.7976931348623157e308))); 190 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1.7976931348623157e308))); 191 } 192 193 @Test 194 public void testIsInfinite() throws Exception { 195 assertTrue((boolean) isInfinite.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 196 assertTrue((boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 197 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, NaN.invoke(null)))); 198 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, 0.0))); 199 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -0.0))); 200 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, 1.0))); 201 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -1.0))); 202 final long min_double64 = 0x0000000000000001L; 203 assertTrue(!(boolean) isInfinite.invoke(null, min_double64)); 204 } 205 206 @Test 207 public void testIsNan() throws Exception { 208 assertTrue((boolean) isNaN.invoke(null, doubleToLong.invoke(null, NaN.invoke(null)))); 209 final long other_nan = 0xFFFFFFFF00000001L; 210 assertTrue((boolean) isNaN.invoke(null, other_nan)); 211 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 212 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 213 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, 0.0))); 214 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -0.0))); 215 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, 1.0))); 216 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -1.0))); 217 final long min_double64 = 0x0000000000000001L; 218 assertTrue(!(boolean) isNaN.invoke(null, min_double64)); 219 } 220 221 @Test 222 public void testSign() throws Exception { 223 assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, 1.0))); 224 assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 225 assertEquals(-1, (int) sign.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 226 assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, 0.0))); 227 assertEquals(-1, (int) sign.invoke(null, doubleToLong.invoke(null, -0.0))); 228 final long min_double64 = 0x0000000000000001L; 229 assertEquals(1, (int) sign.invoke(null, min_double64)); 230 } 231 232 @Test 233 public void testNormalizedBoundaries() throws Exception { 234 Object boundary_plus = DiyFpCtor.newInstance(); 235 Object boundary_minus = DiyFpCtor.newInstance(); 236 Object diy_fp = asNormalizedDiyFp.invoke(null, doubleToLong.invoke(null, 1.5)); 237 normalizedBoundaries.invoke(null, doubleToLong.invoke(null, 1.5), boundary_minus, boundary_plus); 238 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 239 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 240 // 1.5 does not have a significand of the form 2^p (for some p). 241 // Therefore its boundaries are at the same distance. 242 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 243 assertTrue((1 << 10) == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 244 245 diy_fp =asNormalizedDiyFp.invoke(null, doubleToLong.invoke(null, 1.0)); 246 normalizedBoundaries.invoke(null, doubleToLong.invoke(null, 1.0), boundary_minus, boundary_plus); 247 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 248 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 249 // 1.0 does have a significand of the form 2^p (for some p). 250 // Therefore its lower boundary is twice as close as the upper boundary. 251 assertTrue((long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp) > (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 252 assertTrue((1L << 9) == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 253 assertTrue((1L << 10) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 254 255 final long min_double64 = 0x0000000000000001L; 256 diy_fp = asNormalizedDiyFp.invoke(null, min_double64); 257 normalizedBoundaries.invoke(null, min_double64, boundary_minus, boundary_plus); 258 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 259 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 260 // min-value does not have a significand of the form 2^p (for some p). 261 // Therefore its boundaries are at the same distance. 262 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 263 // Denormals have their boundaries much closer. 264 assertTrue(1L << 62 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 265 266 final long smallest_normal64 = 0x0010000000000000L; 267 diy_fp = asNormalizedDiyFp.invoke(null, smallest_normal64); 268 normalizedBoundaries.invoke(null, smallest_normal64, boundary_minus, boundary_plus); 269 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 270 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 271 // Even though the significand is of the form 2^p (for some p), its boundaries 272 // are at the same distance. (This is the only exception). 273 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 274 assertTrue(1L << 10 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 275 276 final long largest_denormal64 = 0x000FFFFFFFFFFFFFL; 277 diy_fp = asNormalizedDiyFp.invoke(null, largest_denormal64); 278 normalizedBoundaries.invoke(null, largest_denormal64, boundary_minus, boundary_plus); 279 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 280 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 281 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 282 assertTrue(1L << 11 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 283 284 final long max_double64 = 0x7fefffffffffffffL; 285 diy_fp = asNormalizedDiyFp.invoke(null, max_double64); 286 normalizedBoundaries.invoke(null, max_double64, boundary_minus, boundary_plus); 287 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 288 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 289 // max-value does not have a significand of the form 2^p (for some p). 290 // Therefore its boundaries are at the same distance. 291 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 292 assertTrue(1L << 10 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 293 } 294 295 @Test 296 public void testNextDouble() throws Exception { 297 assertEquals(4e-324, (double) nextDouble.invoke(null, doubleToLong.invoke(null, 0.0))); 298 assertEquals(0.0, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -0.0))); 299 assertEquals(-0.0, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -4e-324))); 300 assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, nextDouble.invoke(null, doubleToLong.invoke(null, -0.0)))) > 0); 301 assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, nextDouble.invoke(null, doubleToLong.invoke(null, -4e-324)))) < 0); 302 final long d0 = (long) doubleToLong.invoke(null, -4e-324); 303 final long d1 = (long) doubleToLong.invoke(null, nextDouble.invoke(null, d0)); 304 final long d2 = (long) doubleToLong.invoke(null, nextDouble.invoke(null, d1)); 305 assertEquals(-0.0, value.invoke(null, d1)); 306 assertTrue((int) sign.invoke(null, d1) < 0); 307 assertEquals(0.0, value.invoke(null, d2)); 308 assertTrue((int) sign.invoke(null, d2) > 0); 309 assertEquals(4e-324, (double) nextDouble.invoke(null, d2)); 310 assertEquals(-1.7976931348623157e308, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 311 assertEquals(Infinity.invoke(null), (double) nextDouble.invoke(null, 0x7fefffffffffffffL)); 312 } 313 314 @Test 315 public void testPreviousDouble() throws Exception { 316 assertEquals(0.0, (double) previousDouble.invoke(null, doubleToLong.invoke(null, 4e-324))); 317 assertEquals(-0.0, (double) previousDouble.invoke(null, doubleToLong.invoke(null, 0.0))); 318 assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, previousDouble.invoke(null, doubleToLong.invoke(null, 0.0)))) < 0); 319 assertEquals(-4e-324, previousDouble.invoke(null, doubleToLong.invoke(null, -0.0))); 320 final long d0 = (long) doubleToLong.invoke(null, 4e-324); 321 final long d1 = (long) doubleToLong.invoke(null, previousDouble.invoke(null, d0)); 322 final long d2 = (long) doubleToLong.invoke(null, previousDouble.invoke(null, d1)); 323 assertEquals(0.0, value.invoke(null, d1)); 324 assertTrue((int) sign.invoke(null, d1) > 0); 325 assertEquals(-0.0, value.invoke(null, d2)); 326 assertTrue((int) sign.invoke(null, d2) < 0); 327 assertEquals(-4e-324, (double) previousDouble.invoke(null, d2)); 328 assertEquals(1.7976931348623157e308, (double) previousDouble.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 329 assertEquals(-(double) Infinity.invoke(null), (double) previousDouble.invoke(null, 0xffefffffffffffffL)); 330 } 331 332 }