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 33package jdk.nashorn.internal.runtime.doubleconv.test; 34 35import org.testng.annotations.Test; 36 37import java.lang.reflect.Constructor; 38import java.lang.reflect.Method; 39 40import static org.testng.Assert.assertEquals; 41import static org.testng.Assert.assertTrue; 42 43/** 44 * Ieee class tests 45 */ 46@SuppressWarnings({"unchecked", "javadoc"}) 47public class IeeeDoubleTest { 48 49 static final Method asDiyFp; 50 static final Method asNormalizedDiyFp; 51 static final Method doubleToLong; 52 static final Method longToDouble; 53 static final Method isDenormal; 54 static final Method isSpecial; 55 static final Method isInfinite; 56 static final Method isNaN; 57 static final Method value; 58 static final Method sign; 59 static final Method nextDouble; 60 static final Method previousDouble; 61 static final Method normalizedBoundaries; 62 static final Method Infinity; 63 static final Method NaN; 64 static final Method f; 65 static final Method e; 66 static final Constructor<?> DiyFpCtor; 67 68 static { 69 try { 70 final Class<?> IeeeDouble = Class.forName("jdk.nashorn.internal.runtime.doubleconv.IeeeDouble"); 71 final Class DiyFp = Class.forName("jdk.nashorn.internal.runtime.doubleconv.DiyFp"); 72 asDiyFp = method(IeeeDouble, "asDiyFp", long.class); 73 asNormalizedDiyFp = method(IeeeDouble, "asNormalizedDiyFp", long.class); 74 doubleToLong = method(IeeeDouble, "doubleToLong", double.class); 75 longToDouble = method(IeeeDouble, "longToDouble", long.class); 76 isDenormal = method(IeeeDouble, "isDenormal", long.class); 77 isSpecial = method(IeeeDouble, "isSpecial", long.class); 78 isInfinite = method(IeeeDouble, "isInfinite", long.class); 79 isNaN = method(IeeeDouble, "isNaN", long.class); 80 value = method(IeeeDouble, "value", long.class); 81 sign = method(IeeeDouble, "sign", long.class); 82 nextDouble = method(IeeeDouble, "nextDouble", long.class); 83 previousDouble = method(IeeeDouble, "previousDouble", long.class); 84 Infinity = method(IeeeDouble, "Infinity"); 85 NaN = method(IeeeDouble, "NaN"); 86 normalizedBoundaries = method(IeeeDouble, "normalizedBoundaries", long.class, DiyFp, DiyFp); 87 DiyFpCtor = DiyFp.getDeclaredConstructor(); 88 DiyFpCtor.setAccessible(true); 89 f = method(DiyFp, "f"); 90 e = method(DiyFp, "e"); 91 } catch (final Exception e) { 92 throw new RuntimeException(e); 93 } 94 } 95 96 private static Method method(final Class<?> clazz, final String name, final Class<?>... params) throws NoSuchMethodException { 97 final Method m = clazz.getDeclaredMethod(name, params); 98 m.setAccessible(true); 99 return m; 100 } 101 102 @Test 103 public void testUint64Conversions() throws Exception { 104 // Start by checking the byte-order. 105 final long ordered = 0x0123456789ABCDEFL; 106 assertEquals(3512700564088504e-318, value.invoke(null, ordered)); 107 108 final long min_double64 = 0x0000000000000001L; 109 assertEquals(5e-324, value.invoke(null, min_double64)); 110 111 final long max_double64 = 0x7fefffffffffffffL; 112 assertEquals(1.7976931348623157e308, value.invoke(null, max_double64)); 113 } 114 115 116 @Test 117 public void testDoubleAsDiyFp() throws Exception { 118 final long ordered = 0x0123456789ABCDEFL; 119 Object diy_fp = asDiyFp.invoke(null, ordered); 120 assertEquals(0x12 - 0x3FF - 52, e.invoke(diy_fp)); 121 // The 52 mantissa bits, plus the implicit 1 in bit 52 as a UINT64. 122 assertTrue(0x0013456789ABCDEFL == (long) f.invoke(diy_fp)); 123 124 final long min_double64 = 0x0000000000000001L; 125 diy_fp = asDiyFp.invoke(null, min_double64); 126 assertEquals(-0x3FF - 52 + 1, e.invoke(diy_fp)); 127 // This is a denormal; so no hidden bit. 128 assertTrue(1L == (long) f.invoke(diy_fp)); 129 130 final long max_double64 = 0x7fefffffffffffffL; 131 diy_fp = asDiyFp.invoke(null, max_double64); 132 assertEquals(0x7FE - 0x3FF - 52, e.invoke(diy_fp)); 133 assertTrue(0x001fffffffffffffL == (long) f.invoke(diy_fp)); 134 } 135 136 137 @Test 138 public void testAsNormalizedDiyFp() throws Exception { 139 final long ordered = 0x0123456789ABCDEFL; 140 Object diy_fp = asNormalizedDiyFp.invoke(null, ordered); 141 assertEquals(0x12 - 0x3FF - 52 - 11, (int) e.invoke(diy_fp)); 142 assertTrue((0x0013456789ABCDEFL << 11) == (long) f.invoke(diy_fp)); 143 144 final long min_double64 = 0x0000000000000001L; 145 diy_fp = asNormalizedDiyFp.invoke(null, min_double64); 146 assertEquals(-0x3FF - 52 + 1 - 63, e.invoke(diy_fp)); 147 // This is a denormal; so no hidden bit. 148 assertTrue(0x8000000000000000L == (long) f.invoke(diy_fp)); 149 150 final long max_double64 = 0x7fefffffffffffffL; 151 diy_fp = asNormalizedDiyFp.invoke(null, max_double64); 152 assertEquals(0x7FE - 0x3FF - 52 - 11, e.invoke(diy_fp)); 153 assertTrue((0x001fffffffffffffL << 11) == (long) f.invoke(diy_fp)); 154 } 155 156 157 @Test 158 public void testIsDenormal() throws Exception { 159 final long min_double64 = 0x0000000000000001L; 160 assertTrue((boolean) isDenormal.invoke(null, min_double64)); 161 long bits = 0x000FFFFFFFFFFFFFL; 162 assertTrue((boolean) isDenormal.invoke(null, bits)); 163 bits = 0x0010000000000000L; 164 assertTrue(!(boolean) isDenormal.invoke(null, bits)); 165 } 166 167 @Test 168 public void testIsSpecial() throws Exception { 169 assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 170 assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 171 assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, NaN.invoke(null)))); 172 final long bits = 0xFFF1234500000000L; 173 assertTrue((boolean) isSpecial.invoke(null, bits)); 174 // Denormals are not special: 175 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 5e-324))); 176 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -5e-324))); 177 // And some random numbers: 178 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 0.0))); 179 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -0.0))); 180 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1.0))); 181 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1.0))); 182 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1000000.0))); 183 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1000000.0))); 184 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1e23))); 185 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1e23))); 186 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1.7976931348623157e308))); 187 assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1.7976931348623157e308))); 188 } 189 190 @Test 191 public void testIsInfinite() throws Exception { 192 assertTrue((boolean) isInfinite.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 193 assertTrue((boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 194 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, NaN.invoke(null)))); 195 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, 0.0))); 196 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -0.0))); 197 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, 1.0))); 198 assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -1.0))); 199 final long min_double64 = 0x0000000000000001L; 200 assertTrue(!(boolean) isInfinite.invoke(null, min_double64)); 201 } 202 203 @Test 204 public void testIsNan() throws Exception { 205 assertTrue((boolean) isNaN.invoke(null, doubleToLong.invoke(null, NaN.invoke(null)))); 206 final long other_nan = 0xFFFFFFFF00000001L; 207 assertTrue((boolean) isNaN.invoke(null, other_nan)); 208 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 209 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 210 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, 0.0))); 211 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -0.0))); 212 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, 1.0))); 213 assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -1.0))); 214 final long min_double64 = 0x0000000000000001L; 215 assertTrue(!(boolean) isNaN.invoke(null, min_double64)); 216 } 217 218 @Test 219 public void testSign() throws Exception { 220 assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, 1.0))); 221 assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 222 assertEquals(-1, (int) sign.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 223 assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, 0.0))); 224 assertEquals(-1, (int) sign.invoke(null, doubleToLong.invoke(null, -0.0))); 225 final long min_double64 = 0x0000000000000001L; 226 assertEquals(1, (int) sign.invoke(null, min_double64)); 227 } 228 229 @Test 230 public void testNormalizedBoundaries() throws Exception { 231 final Object boundary_plus = DiyFpCtor.newInstance(); 232 final Object boundary_minus = DiyFpCtor.newInstance(); 233 Object diy_fp = asNormalizedDiyFp.invoke(null, doubleToLong.invoke(null, 1.5)); 234 normalizedBoundaries.invoke(null, doubleToLong.invoke(null, 1.5), boundary_minus, boundary_plus); 235 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 236 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 237 // 1.5 does not have a significand of the form 2^p (for some p). 238 // Therefore its boundaries are at the same distance. 239 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 240 assertTrue((1 << 10) == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 241 242 diy_fp =asNormalizedDiyFp.invoke(null, doubleToLong.invoke(null, 1.0)); 243 normalizedBoundaries.invoke(null, doubleToLong.invoke(null, 1.0), boundary_minus, boundary_plus); 244 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 245 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 246 // 1.0 does have a significand of the form 2^p (for some p). 247 // Therefore its lower boundary is twice as close as the upper boundary. 248 assertTrue((long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp) > (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 249 assertTrue((1L << 9) == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 250 assertTrue((1L << 10) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 251 252 final long min_double64 = 0x0000000000000001L; 253 diy_fp = asNormalizedDiyFp.invoke(null, min_double64); 254 normalizedBoundaries.invoke(null, min_double64, boundary_minus, boundary_plus); 255 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 256 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 257 // min-value does not have a significand of the form 2^p (for some p). 258 // Therefore its boundaries are at the same distance. 259 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 260 // Denormals have their boundaries much closer. 261 assertTrue(1L << 62 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 262 263 final long smallest_normal64 = 0x0010000000000000L; 264 diy_fp = asNormalizedDiyFp.invoke(null, smallest_normal64); 265 normalizedBoundaries.invoke(null, smallest_normal64, boundary_minus, boundary_plus); 266 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 267 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 268 // Even though the significand is of the form 2^p (for some p), its boundaries 269 // are at the same distance. (This is the only exception). 270 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 271 assertTrue(1L << 10 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 272 273 final long largest_denormal64 = 0x000FFFFFFFFFFFFFL; 274 diy_fp = asNormalizedDiyFp.invoke(null, largest_denormal64); 275 normalizedBoundaries.invoke(null, largest_denormal64, boundary_minus, boundary_plus); 276 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 277 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 278 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 279 assertTrue(1L << 11 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 280 281 final long max_double64 = 0x7fefffffffffffffL; 282 diy_fp = asNormalizedDiyFp.invoke(null, max_double64); 283 normalizedBoundaries.invoke(null, max_double64, boundary_minus, boundary_plus); 284 assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus)); 285 assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus)); 286 // max-value does not have a significand of the form 2^p (for some p). 287 // Therefore its boundaries are at the same distance. 288 assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp)); 289 assertTrue(1L << 10 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus)); 290 } 291 292 @Test 293 public void testNextDouble() throws Exception { 294 assertEquals(4e-324, (double) nextDouble.invoke(null, doubleToLong.invoke(null, 0.0))); 295 assertEquals(0.0, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -0.0))); 296 assertEquals(-0.0, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -4e-324))); 297 assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, nextDouble.invoke(null, doubleToLong.invoke(null, -0.0)))) > 0); 298 assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, nextDouble.invoke(null, doubleToLong.invoke(null, -4e-324)))) < 0); 299 final long d0 = (long) doubleToLong.invoke(null, -4e-324); 300 final long d1 = (long) doubleToLong.invoke(null, nextDouble.invoke(null, d0)); 301 final long d2 = (long) doubleToLong.invoke(null, nextDouble.invoke(null, d1)); 302 assertEquals(-0.0, value.invoke(null, d1)); 303 assertTrue((int) sign.invoke(null, d1) < 0); 304 assertEquals(0.0, value.invoke(null, d2)); 305 assertTrue((int) sign.invoke(null, d2) > 0); 306 assertEquals(4e-324, (double) nextDouble.invoke(null, d2)); 307 assertEquals(-1.7976931348623157e308, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null)))); 308 assertEquals(Infinity.invoke(null), (double) nextDouble.invoke(null, 0x7fefffffffffffffL)); 309 } 310 311 @Test 312 public void testPreviousDouble() throws Exception { 313 assertEquals(0.0, (double) previousDouble.invoke(null, doubleToLong.invoke(null, 4e-324))); 314 assertEquals(-0.0, (double) previousDouble.invoke(null, doubleToLong.invoke(null, 0.0))); 315 assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, previousDouble.invoke(null, doubleToLong.invoke(null, 0.0)))) < 0); 316 assertEquals(-4e-324, previousDouble.invoke(null, doubleToLong.invoke(null, -0.0))); 317 final long d0 = (long) doubleToLong.invoke(null, 4e-324); 318 final long d1 = (long) doubleToLong.invoke(null, previousDouble.invoke(null, d0)); 319 final long d2 = (long) doubleToLong.invoke(null, previousDouble.invoke(null, d1)); 320 assertEquals(0.0, value.invoke(null, d1)); 321 assertTrue((int) sign.invoke(null, d1) > 0); 322 assertEquals(-0.0, value.invoke(null, d2)); 323 assertTrue((int) sign.invoke(null, d2) < 0); 324 assertEquals(-4e-324, (double) previousDouble.invoke(null, d2)); 325 assertEquals(1.7976931348623157e308, (double) previousDouble.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null)))); 326 assertEquals(-(double) Infinity.invoke(null), (double) previousDouble.invoke(null, 0xffefffffffffffffL)); 327 } 328 329} 330