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 2012 the V8 project authors. All rights reserved.
  32 // Redistribution and use in source and binary forms, with or without
  33 // modification, are permitted provided that the following conditions are
  34 // met:
  35 //
  36 //     * Redistributions of source code must retain the above copyright
  37 //       notice, this list of conditions and the following disclaimer.
  38 //     * Redistributions in binary form must reproduce the above
  39 //       copyright notice, this list of conditions and the following
  40 //       disclaimer in the documentation and/or other materials provided
  41 //       with the distribution.
  42 //     * Neither the name of Google Inc. nor the names of its
  43 //       contributors may be used to endorse or promote products derived
  44 //       from this software without specific prior written permission.
  45 //
  46 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  47 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  48 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  49 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  50 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  51 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  52 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  53 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  54 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  55 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  56 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  57 
  58 package jdk.nashorn.internal.runtime.doubleconv.test;
  59 
  60 import java.io.BufferedReader;
  61 import java.io.InputStreamReader;
  62 import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
  63 import jdk.nashorn.internal.runtime.doubleconv.DtoaBuffer;
  64 import jdk.nashorn.internal.runtime.doubleconv.DtoaMode;
  65 
  66 import org.testng.annotations.Test;
  67 
  68 import static org.testng.Assert.assertEquals;
  69 import static org.testng.Assert.assertTrue;
  70 
  71 /**
  72  * BignumDtoa tests
  73  */
  74 @SuppressWarnings("javadoc")
  75 public class BignumDtoaTest {
  76 
  77     final static private int BUFFER_SIZE = 100;
  78 
  79     // Removes trailing '0' digits.
  80     // Can return the empty string if all digits are 0.
  81     private static String trimRepresentation(final String representation) {
  82         final int len = representation.length();
  83         int i;
  84         for (i = len - 1; i >= 0; --i) {
  85             if (representation.charAt(i) != '0') break;
  86         }
  87         return representation.substring(0, i + 1);
  88     }
  89 
  90     @Test
  91     public void testBignumVarious() {
  92         final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
  93 
  94         DoubleConversion.bignumDtoa(1, DtoaMode.SHORTEST, 0, buffer);
  95         assertEquals("1", buffer.getRawDigits());
  96         assertEquals(1, buffer.getDecimalPoint());
  97         buffer.reset();
  98 
  99         DoubleConversion.bignumDtoa(1.0, DtoaMode.FIXED, 3, buffer);
 100         assertTrue(3 >= buffer.getLength() - buffer.getDecimalPoint());
 101         assertEquals("1", trimRepresentation(buffer.getRawDigits()));
 102         assertEquals(1, buffer.getDecimalPoint());
 103         buffer.reset();
 104 
 105         DoubleConversion.bignumDtoa(1.0, DtoaMode.PRECISION, 3, buffer);
 106         assertTrue(3 >= buffer.getLength());
 107         assertEquals("1", trimRepresentation(buffer.getRawDigits()));
 108         assertEquals(1, buffer.getDecimalPoint());
 109         buffer.reset();
 110 
 111         DoubleConversion.bignumDtoa(1.5, DtoaMode.SHORTEST, 0, buffer);
 112         assertEquals("15", buffer.getRawDigits());
 113         assertEquals(1, buffer.getDecimalPoint());
 114         buffer.reset();
 115 
 116         DoubleConversion.bignumDtoa(1.5, DtoaMode.FIXED, 10, buffer);
 117         assertTrue(10 >= buffer.getLength() - buffer.getDecimalPoint());
 118         assertEquals("15", trimRepresentation(buffer.getRawDigits()));
 119         assertEquals(1, buffer.getDecimalPoint());
 120         buffer.reset();
 121 
 122         DoubleConversion.bignumDtoa(1.5, DtoaMode.PRECISION, 10, buffer);
 123         assertTrue(10 >= buffer.getLength());
 124         assertEquals("15", trimRepresentation(buffer.getRawDigits()));
 125         assertEquals(1, buffer.getDecimalPoint());
 126         buffer.reset();
 127 
 128         final double min_double = 5e-324;
 129         DoubleConversion.bignumDtoa(min_double, DtoaMode.SHORTEST, 0, buffer);
 130         assertEquals("5", buffer.getRawDigits());
 131         assertEquals(-323, buffer.getDecimalPoint());
 132         buffer.reset();
 133 
 134         DoubleConversion.bignumDtoa(min_double, DtoaMode.FIXED, 5, buffer);
 135         assertTrue(5 >= buffer.getLength() - buffer.getDecimalPoint());
 136         assertEquals("", trimRepresentation(buffer.getRawDigits()));
 137         buffer.reset();
 138 
 139         DoubleConversion.bignumDtoa(min_double, DtoaMode.PRECISION, 5, buffer);
 140         assertTrue(5 >= buffer.getLength());
 141         assertEquals("49407", trimRepresentation(buffer.getRawDigits()));
 142         assertEquals(-323, buffer.getDecimalPoint());
 143         buffer.reset();
 144 
 145         final double max_double = 1.7976931348623157e308;
 146         DoubleConversion.bignumDtoa(max_double, DtoaMode.SHORTEST, 0, buffer);
 147         assertEquals("17976931348623157", buffer.getRawDigits());
 148         assertEquals(309, buffer.getDecimalPoint());
 149         buffer.reset();
 150 
 151         DoubleConversion.bignumDtoa(max_double, DtoaMode.PRECISION, 7, buffer);
 152         assertTrue(7 >= buffer.getLength());
 153         assertEquals("1797693", trimRepresentation(buffer.getRawDigits()));
 154         assertEquals(309, buffer.getDecimalPoint());
 155         buffer.reset();
 156 
 157         DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.SHORTEST, 0, buffer);
 158         assertEquals("4294967272", buffer.getRawDigits());
 159         assertEquals(10, buffer.getDecimalPoint());
 160         buffer.reset();
 161 
 162         DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.FIXED, 5, buffer);
 163         assertEquals("429496727200000", buffer.getRawDigits());
 164         assertEquals(10, buffer.getDecimalPoint());
 165         buffer.reset();
 166 
 167         DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.PRECISION, 14, buffer);
 168         assertTrue(14 >= buffer.getLength());
 169         assertEquals("4294967272", trimRepresentation(buffer.getRawDigits()));
 170         assertEquals(10, buffer.getDecimalPoint());
 171         buffer.reset();
 172 
 173         DoubleConversion.bignumDtoa(4.1855804968213567e298, DtoaMode.SHORTEST, 0, buffer);
 174         assertEquals("4185580496821357", buffer.getRawDigits());
 175         assertEquals(299, buffer.getDecimalPoint());
 176         buffer.reset();
 177 
 178         DoubleConversion.bignumDtoa(4.1855804968213567e298, DtoaMode.PRECISION, 20, buffer);
 179         assertTrue(20 >= buffer.getLength());
 180         assertEquals("41855804968213567225", trimRepresentation(buffer.getRawDigits()));
 181         assertEquals(299, buffer.getDecimalPoint());
 182         buffer.reset();
 183 
 184         DoubleConversion.bignumDtoa(5.5626846462680035e-309, DtoaMode.SHORTEST, 0, buffer);
 185         assertEquals("5562684646268003", buffer.getRawDigits());
 186         assertEquals(-308, buffer.getDecimalPoint());
 187         buffer.reset();
 188 
 189         DoubleConversion.bignumDtoa(5.5626846462680035e-309, DtoaMode.PRECISION, 1, buffer);
 190         assertTrue(1 >= buffer.getLength());
 191         assertEquals("6", trimRepresentation(buffer.getRawDigits()));
 192         assertEquals(-308, buffer.getDecimalPoint());
 193         buffer.reset();
 194 
 195         DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.SHORTEST, 0, buffer);
 196         assertEquals("2147483648", buffer.getRawDigits());
 197         assertEquals(10, buffer.getDecimalPoint());
 198         buffer.reset();
 199 
 200         DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.FIXED, 2, buffer);
 201         assertTrue(2 >= buffer.getLength() - buffer.getDecimalPoint());
 202         assertEquals("2147483648", trimRepresentation(buffer.getRawDigits()));
 203         assertEquals(10, buffer.getDecimalPoint());
 204         buffer.reset();
 205 
 206         DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.PRECISION, 5, buffer);
 207         assertTrue(5 >= buffer.getLength());
 208         assertEquals("21475", trimRepresentation(buffer.getRawDigits()));
 209         assertEquals(10, buffer.getDecimalPoint());
 210         buffer.reset();
 211 
 212         DoubleConversion.bignumDtoa(3.5844466002796428e+298, DtoaMode.SHORTEST, 0, buffer);
 213         assertEquals("35844466002796428", buffer.getRawDigits());
 214         assertEquals(299, buffer.getDecimalPoint());
 215         buffer.reset();
 216 
 217         DoubleConversion.bignumDtoa(3.5844466002796428e+298, DtoaMode.PRECISION, 10, buffer);
 218         assertTrue(10 >= buffer.getLength());
 219         assertEquals("35844466", trimRepresentation(buffer.getRawDigits()));
 220         assertEquals(299, buffer.getDecimalPoint());
 221         buffer.reset();
 222 
 223         DoubleConversion.bignumDtoa(1e-23, DtoaMode.SHORTEST, 0, buffer);
 224         assertEquals("1", buffer.getRawDigits());
 225         assertEquals(-22, buffer.getDecimalPoint());
 226         buffer.reset();
 227 
 228         final long smallest_normal64 = 0x0010000000000000L;
 229         double v = Double.longBitsToDouble(smallest_normal64);
 230         DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
 231         assertEquals("22250738585072014", buffer.getRawDigits());
 232         assertEquals(-307, buffer.getDecimalPoint());
 233         buffer.reset();
 234 
 235         DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 20, buffer);
 236         assertTrue(20 >= buffer.getLength());
 237         assertEquals("22250738585072013831", trimRepresentation(buffer.getRawDigits()));
 238         assertEquals(-307, buffer.getDecimalPoint());
 239         buffer.reset();
 240 
 241         final long largest_denormal64 = 0x000FFFFFFFFFFFFFL;
 242         v = Double.longBitsToDouble(largest_denormal64);
 243         DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
 244         assertEquals("2225073858507201", buffer.getRawDigits());
 245         assertEquals(-307, buffer.getDecimalPoint());
 246         buffer.reset();
 247 
 248         DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 20, buffer);
 249         assertTrue(20 >= buffer.getLength());
 250         assertEquals("2225073858507200889", trimRepresentation(buffer.getRawDigits()));
 251         assertEquals(-307, buffer.getDecimalPoint());
 252         buffer.reset();
 253 
 254         DoubleConversion.bignumDtoa(4128420500802942e-24, DtoaMode.SHORTEST, 0, buffer);
 255         assertEquals("4128420500802942", buffer.getRawDigits());
 256         assertEquals(-8, buffer.getDecimalPoint());
 257         buffer.reset();
 258 
 259         DoubleConversion.bignumDtoa(3.9292015898194142585311918e-10, DtoaMode.SHORTEST, 0, buffer);
 260         assertEquals("39292015898194143", buffer.getRawDigits());
 261         buffer.reset();
 262 
 263         v = 4194304.0;
 264         DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, 5, buffer);
 265         assertTrue(5 >= buffer.getLength() - buffer.getDecimalPoint());
 266         assertEquals("4194304", trimRepresentation(buffer.getRawDigits()));
 267         buffer.reset();
 268 
 269         v = 3.3161339052167390562200598e-237;
 270         DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 19, buffer);
 271         assertTrue(19 >= buffer.getLength());
 272         assertEquals("3316133905216739056", trimRepresentation(buffer.getRawDigits()));
 273         assertEquals(-236, buffer.getDecimalPoint());
 274         buffer.reset();
 275 
 276         v = 7.9885183916008099497815232e+191;
 277         DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 4, buffer);
 278         assertTrue(4 >= buffer.getLength());
 279         assertEquals("7989", trimRepresentation(buffer.getRawDigits()));
 280         assertEquals(192, buffer.getDecimalPoint());
 281         buffer.reset();
 282 
 283         v = 1.0000000000000012800000000e+17;
 284         DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, 1, buffer);
 285         assertTrue(1 >= buffer.getLength() - buffer.getDecimalPoint());
 286         assertEquals("100000000000000128", trimRepresentation(buffer.getRawDigits()));
 287         assertEquals(18, buffer.getDecimalPoint());
 288         buffer.reset();
 289     }
 290 
 291 
 292     @Test
 293     public void testBignumShortest() {
 294         new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-shortest.txt")))
 295                 .lines()
 296                 .forEach(line -> {
 297                     if (line.isEmpty() || line.startsWith("//")) {
 298                         return; // comment or empty line
 299                     }
 300                     final String[] tokens = line.split(",\\s+");
 301                     assertEquals(tokens.length, 3, "*" + line + "*");
 302                     final double v = Double.parseDouble(tokens[0]);
 303                     final String str = tokens[1].replace('"', ' ').trim();;
 304                     final int point = Integer.parseInt(tokens[2]);
 305                     final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
 306 
 307                     DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
 308                     assertEquals(str, buffer.getRawDigits());
 309                     assertEquals(point, buffer.getDecimalPoint());
 310                 });
 311     }
 312 
 313     @Test
 314     public void testBignumFixed()  {
 315         new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-fixed.txt")))
 316                 .lines()
 317                 .forEach(line -> {
 318                     if (line.isEmpty() || line.startsWith("//")) {
 319                         return; // comment or empty line
 320                     }
 321                     final String[] tokens = line.split(",\\s+");
 322                     assertEquals(tokens.length, 4);
 323                     final double v = Double.parseDouble(tokens[0]);
 324                     final int digits = Integer.parseInt(tokens[1]);
 325                     final String str = tokens[2].replace('"', ' ').trim();
 326                     final int point = Integer.parseInt(tokens[3]);
 327                     final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
 328 
 329                     DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, digits, buffer);
 330                     assertEquals(str, trimRepresentation(buffer.getRawDigits()));
 331                     assertEquals(point, buffer.getDecimalPoint());
 332                 });
 333     }
 334 
 335     @Test
 336     public void testBignumPrecision() {
 337         new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-precision.txt")))
 338                 .lines()
 339                 .forEach(line -> {
 340                     if (line.isEmpty() || line.startsWith("//")) {
 341                         return; // comment or empty line
 342                     }
 343                     final String[] tokens = line.split(",\\s+");
 344                     assertEquals(tokens.length, 4);
 345                     final double v = Double.parseDouble(tokens[0]);
 346                     final int digits = Integer.parseInt(tokens[1]);
 347                     final String str = tokens[2].replace('"', ' ').trim();
 348                     final int point = Integer.parseInt(tokens[3]);
 349                     final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
 350 
 351                     DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, digits, buffer);
 352                     assertEquals(str, trimRepresentation(buffer.getRawDigits()));
 353                     assertEquals(point, buffer.getDecimalPoint());
 354                 });
 355     }
 356 
 357 }