1 /*
2  * Copyright (c) 2003, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package test.java.math.BigDecimal;
24 
25 /*
26  * @test
27  * @bug 4902952 4905407 4916149 8057793
28  * @summary Tests that the scale of zero is propagated properly and has the
29  * proper effect and that setting the scale to zero does not mutate the
30  * BigDecimal.
31  * @author Joseph D. Darcy
32  */
33 
34 import java.math.*;
35 import java.util.*;
36 
37 import org.testng.Assert;
38 import org.testng.annotations.Test;
39 
40 // Android-changed: Replace error counting with asserts.
41 public class ZeroScalingTests {
42 
43     static MathContext longEnough = new MathContext(50, RoundingMode.UNNECESSARY);
44 
45     static BigDecimal[]  zeros = new BigDecimal[23];
46     static {
47         for(int i = 0; i < 21; i++) {
48             zeros[i] = new BigDecimal(BigInteger.ZERO, i-10);
49         }
50         zeros[21] = new BigDecimal(BigInteger.ZERO, Integer.MIN_VALUE);
51         zeros[22] = new BigDecimal(BigInteger.ZERO, Integer.MAX_VALUE);
52     }
53 
54     static BigDecimal element = BigDecimal.valueOf(100, -2);
55 
56     static MathContext[] contexts = {
57         new MathContext(0, RoundingMode.UNNECESSARY),
58         new MathContext(100, RoundingMode.UNNECESSARY),
59         new MathContext(5, RoundingMode.UNNECESSARY),
60         new MathContext(4, RoundingMode.UNNECESSARY),
61         new MathContext(3, RoundingMode.UNNECESSARY),
62         new MathContext(2, RoundingMode.UNNECESSARY),
63         new MathContext(1, RoundingMode.UNNECESSARY),
64     };
65 
66 
67     @Test
addTests()68     public void addTests() {
69         for(BigDecimal zero1: zeros) {
70             for(BigDecimal zero2: zeros) {
71                 BigDecimal expected = new BigDecimal(BigInteger.ZERO,
72                                                      Math.max(zero1.scale(), zero2.scale()));
73                 BigDecimal result = zero1.add(zero2);
74 
75                 Assert.assertEquals(result, expected, "For classic exact add, expected scale of " +
76                            expected.scale() + "; got " +
77                            result.scale() + ".");
78 
79                 result = zero1.add(zero2, MathContext.UNLIMITED);
80                 Assert.assertEquals(result, expected, "For UNLIMITED math context add," +
81                            " expected scale of " +
82                            expected.scale() + "; got " +
83                            result.scale() + ".");
84 
85                 result = zero1.add(zero2, longEnough);
86                 Assert.assertEquals(result, expected, "For longEnough math context add," +
87                            " expected scale of " +
88                            expected.scale() + "; got " +
89                            result.scale() + ".");
90             }
91         }
92 
93         // Test effect of adding zero to a nonzero value.
94         for (MathContext mc: contexts) {
95             for (BigDecimal zero: zeros) {
96                 if (Math.abs((long)zero.scale()) < 100 ) {
97 
98                     int preferredScale = Math.max(zero.scale(), element.scale());
99                     if (mc.getPrecision() != 0) {
100                         if (preferredScale < -4 )
101                             preferredScale = -4;
102                         else if (preferredScale > -(5 - mc.getPrecision())) {
103                             preferredScale = -(5 - mc.getPrecision());
104                         }
105                     }
106 
107                     BigDecimal result = element.add(zero, mc);
108                     Assert.assertFalse(result.scale() != preferredScale ||
109                             result.compareTo(element) != 0,
110                         "Expected scale  " + preferredScale +
111                                " result scale was " + result.scale() +
112                                " ; value was " + result);
113 
114                     result = zero.add(element, mc);
115                     Assert.assertFalse(result.scale() != preferredScale ||
116                             result.compareTo(element) != 0,
117                         "Expected scale  " + preferredScale +
118                                    " result scale was " + result.scale() +
119                                    " ; value was " + result);
120 
121                     result = element.negate().add(zero, mc);
122                     Assert.assertFalse(result.scale() != preferredScale ||
123                             result.compareTo(element.negate()) != 0,
124                         "Expected scale  " + preferredScale +
125                                    " result scale was " + result.scale() +
126                                    " ; value was " + result);
127 
128                     result = zero.add(element.negate(), mc);
129                     Assert.assertFalse(result.scale() != preferredScale ||
130                             result.compareTo(element.negate()) != 0,
131                         "Expected scale  " + preferredScale +
132                                    " result scale was " + result.scale() +
133                                    " ; value was " + result);
134                 }
135             }
136         }
137     }
138 
139     @Test
subtractTests()140     public void subtractTests() {
141         for(BigDecimal zero1: zeros) {
142             for(BigDecimal zero2: zeros) {
143                 BigDecimal expected = new BigDecimal(BigInteger.ZERO,
144                                                      Math.max(zero1.scale(), zero2.scale()));
145                 BigDecimal result = zero1.subtract(zero2);
146 
147                 Assert.assertEquals(result, expected,
148                     "For classic exact subtract, expected scale of " +
149                                expected.scale() + "; got " +
150                                result.scale() + ".");
151 
152                 result = zero1.subtract(zero2, MathContext.UNLIMITED);
153                 Assert.assertEquals(result, expected, "For UNLIMITED math context subtract," +
154                            " expected scale of " +
155                            expected.scale() + "; got " +
156                            result.scale() + ".");
157 
158                 result = zero1.subtract(zero2, longEnough);
159                 Assert.assertEquals(result, expected, "For longEnough math context subtract," +
160                            " expected scale of " +
161                            expected.scale() + "; got " +
162                            result.scale() + ".");
163             }
164         }
165 
166 
167         // Test effect of adding zero to a nonzero value.
168         for (MathContext mc: contexts) {
169             for (BigDecimal zero: zeros) {
170                 if (Math.abs((long)zero.scale()) < 100 ) {
171 
172                     int preferredScale = Math.max(zero.scale(), element.scale());
173                     if (mc.getPrecision() != 0) {
174                         if (preferredScale < -4 )
175                             preferredScale = -4;
176                         else if (preferredScale > -(5 - mc.getPrecision())) {
177                             preferredScale = -(5 - mc.getPrecision());
178                         }
179                     }
180 
181                     BigDecimal result = element.subtract(zero, mc);
182                     Assert.assertFalse(result.scale() != preferredScale ||
183                             result.compareTo(element) != 0,
184                         "Expected scale  " + preferredScale +
185                                            " result scale was " + result.scale() +
186                                            " ; value was " + result);
187 
188                     result = zero.subtract(element, mc);
189                     Assert.assertFalse(result.scale() != preferredScale ||
190                             result.compareTo(element.negate()) != 0,
191                         "Expected scale  " + preferredScale +
192                                    " result scale was " + result.scale() +
193                                    " ; value was " + result);
194 
195                     result = element.negate().subtract(zero, mc);
196                     Assert.assertFalse(result.scale() != preferredScale ||
197                             result.compareTo(element.negate()) != 0,
198                         "Expected scale  " + preferredScale +
199                                    " result scale was " + result.scale() +
200                                    " ; value was " + result);
201 
202                     result = zero.subtract(element.negate(), mc);
203                     Assert.assertFalse(result.scale() != preferredScale ||
204                             result.compareTo(element) != 0,
205                         "Expected scale  " + preferredScale +
206                                    " result scale was " + result.scale() +
207                                    " ; value was " + result);
208                 }
209             }
210         }
211     }
212 
213     @Test
multiplyTests()214     public void multiplyTests() {
215         BigDecimal[] ones = {
216             BigDecimal.valueOf(1, 0),
217             BigDecimal.valueOf(10, 1),
218             BigDecimal.valueOf(1000, 3),
219             BigDecimal.valueOf(100000000, 8),
220         };
221 
222         List<BigDecimal> values = new LinkedList<BigDecimal>();
223         values.addAll(Arrays.asList(zeros));
224         values.addAll(Arrays.asList(ones));
225 
226         for(BigDecimal zero1: zeros) {
227             for(BigDecimal value: values) {
228                 BigDecimal expected = new BigDecimal(BigInteger.ZERO,
229                                                      (int)Math.min(Math.max((long)zero1.scale()+value.scale(),
230                                                                             Integer.MIN_VALUE ),
231                                                                    Integer.MAX_VALUE ) );
232                 BigDecimal result = zero1.multiply(value);
233 
234                 Assert.assertEquals(result, expected,
235                     "For classic exact multiply, expected scale of " +
236                                expected.scale() + "; got " +
237                                result.scale() + ".");
238 
239                 result = zero1.multiply(value, MathContext.UNLIMITED);
240                 Assert.assertEquals(result, expected, "For UNLIMITED math context multiply," +
241                                        " expected scale of " +
242                                        expected.scale() + "; got " +
243                                        result.scale() + ".");
244 
245                 result = zero1.multiply(value, longEnough);
246                 Assert.assertEquals(result, expected, "For longEnough math context multiply," +
247                            " expected scale of " +
248                            expected.scale() + "; got " +
249                            result.scale() + ".");
250             }
251         }
252     }
253 
254     @Test
divideTests()255     public void divideTests() {
256         BigDecimal [] ones = {
257             BigDecimal.valueOf(1, 0),
258             BigDecimal.valueOf(10, -1),
259             BigDecimal.valueOf(100, -2),
260             BigDecimal.valueOf(1000, -3),
261             BigDecimal.valueOf(1000000, -5),
262         };
263 
264         for(BigDecimal one: ones) {
265             for(BigDecimal zero: zeros) {
266                 BigDecimal expected = new BigDecimal(BigInteger.ZERO,
267                                                      (int)Math.min(Math.max((long)zero.scale() - one.scale(),
268                                                                             Integer.MIN_VALUE ),
269                                                                    Integer.MAX_VALUE ) );
270                 BigDecimal result = zero.divide(one);
271 
272                 Assert.assertEquals(result, expected, "For classic exact divide, expected scale of " +
273                                expected.scale() + "; got " +
274                                result.scale() + ".");
275 
276                 result = zero.divide(one, MathContext.UNLIMITED);
277                 Assert.assertEquals(result, expected, "For UNLIMITED math context divide," +
278                                " expected scale of " +
279                                expected.scale() + "; got " +
280                                result.scale() + ".");
281 
282                 result = zero.divide(one, longEnough);
283                 Assert.assertEquals(result, expected, "For longEnough math context divide," +
284                                " expected scale of " +
285                                expected.scale() + "; got " +
286                                result.scale() + ".");
287             }
288         }
289     }
290 
291     @Test
setScaleTests()292     public void setScaleTests() {
293         int[] scales = {
294             Integer.MIN_VALUE,
295             Integer.MIN_VALUE+1,
296             -10000000,
297             -3,
298             -2,
299             -1,
300             0,
301             1,
302             2,
303             3,
304             10,
305             10000000,
306             Integer.MAX_VALUE-1,
307             Integer.MAX_VALUE
308         };
309 
310         for(BigDecimal zero: zeros) {
311             for(int scale: scales) {
312                 try {
313                     BigDecimal bd = zero.setScale(scale);
314                 }
315                 catch (ArithmeticException e) {
316                     Assert.fail("Exception when trying to set a scale of " + scale + " on " + zero);
317                 }
318             }
319         }
320     }
321 
322     @Test
toEngineeringStringTests()323     public void toEngineeringStringTests() {
324         String [][] testCases  = {
325             {"0E+10",   "0.00E+12"},
326             {"0E+9",    "0E+9"},
327             {"0E+8",    "0.0E+9"},
328             {"0E+7",    "0.00E+9"},
329 
330             {"0E-10",   "0.0E-9"},
331             {"0E-9",    "0E-9"},
332             {"0E-8",    "0.00E-6"},
333             {"0E-7",    "0.0E-6"},
334         };
335 
336         for(String[] testCase: testCases) {
337             BigDecimal bd = new BigDecimal(testCase[0]);
338             String result = bd.toEngineeringString();
339 
340             Assert.assertFalse(!result.equals(testCase[1]) || !bd.equals(new BigDecimal(result)),
341                 "From input ``" + testCase[0] + ",'' " +
342                            " bad engineering string output ``" + result +
343                            "''; expected ``" + testCase[1] + ".''");
344         }
345     }
346 
347     @Test
ulpTests()348     public void ulpTests() {
349         for(BigDecimal zero: zeros) {
350             BigDecimal result;
351             BigDecimal expected = BigDecimal.valueOf(1, zero.scale());
352 
353             result = zero.ulp();
354             Assert.assertEquals(result, expected, "Unexpected ulp value for zero value " +
355                        zero + "; expected " + expected +
356                        ", got " + result);
357         }
358     }
359 
360     @Test
setScaleDoesNotMutateTest()361     public void setScaleDoesNotMutateTest() {
362         BigDecimal total = new BigDecimal("258815507198903607775511093103396443816569106750031264155319238473795838680758514810110764742309284477206138527975952150289602995045050194333030191178778772026538699925775139201970526695485362661420908248887297829319881475178467494779683293036572059595504702727301324759997409522995072582369210284334718757260859794972695026582432867589093687280300148141501712013226636373167978223780290547640482160818746599330924736802844173226042389174403401903999447463440670236056324929325189403433689"
363                 + ".426167432065785331444814035799717606745777287606858873045971898862329763544687891847664736523584843544347118836628373041412918374550458884706686730726101338872517021688769782894793734049819222924171842793485919753186993388451909096042127903835765393729547730953942175461146061715108701615615142134282261293656760570061554783195726716403304101469782303957325142638493327692352838806741611887655695029948975509680496573999174402058593454203190963443179532640446352828089016874853634851387762579319853267317320515941105912189838719919259277721994880193541634872882180184303434360412344059435559680494807415573269199203376126242271766939666939316648575065702750502798973418978204972336924254702551350654650573582614211506856383897692911422458286912085339575875324832979140870119455620532272318122103640233069115700020760625493816902806241630788230268031695140687964931377988962507263990468276009750998066442971308866347136022907166625330623130307555914930120150437900510530537258665172619821272937026713977709974434967165159545592482710663639966781678268622620229577009317698254134914742098420792313931843709810905414336383757407675429663714210967924767434203021205270369316797752411974617662200898086335322218191674846795163102021505555508444216708745911194321674887527227200297039471799580744303346354057273540730643842091810899490590914195225087593013834388801018488174855060306804024894292757613618190472234110859436472645203753139820658279559340251226992556744343475086923568365637919479462424794554522865559888240039662899509652221329892034706445253487898044421278283079233226845124525434586324657471286953226255430662125870993375281512713207125720748163498642795960457639954616530163959004770092547297392499137383176609646505351001304840762905826237024982330597805063521162285806541220110524989649256399233792799406995068469271941269511818994954109392839548141262324660472253632382325038836831429045617036015122388070240133760858500132713255407855625837956886349324981003917084922808187223285051144454915441134217743066575863563572152133978905444998209075763950909784148142018992367290485890072303179512881131769414783097454103103347826517701720263541869335631166977965013552647906729408522950996105479525445916501155305220090853891226367184989434453290788068397817927893708837722255115237672194162924260945492012622891770365546831236789867922136747819364833843397165107825773447549885351449899330007200651144003961228091210630807333236718793283427788965479074476288255387824982443633190938302785760754436525586544523339170400053128503337395428393881357669568532722167493096151221381017320147344991331421789379785964440840684363041795410525097564979585773948558651896834067324427900848255265001498890329859444233861478388742393060996236783742654761350763876989363052609107226398858310051497856931093693697981165801539060516895227818925342535261227134364063673285588256280386915163875872231395348293505967057794409379709079685798908660258077792158532257603211711587587586356431658240229896344639704");
364 
365         Assert.assertEquals(total.setScale(0, RoundingMode.DOWN),
366              total.setScale(0, RoundingMode.DOWN));
367     }
368 }
369