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.
trimRepresentation(final String representation)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
testBignumVarious()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
testBignumShortest()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
testBignumFixed()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
testBignumPrecision()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 }
358