1 /*
   2  * Copyright 2006 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 6362557
  27  * @summary Some tests of add(BigDecimal, mc)
  28  * @author Joseph D. Darcy
  29  */
  30 
  31 import java.math.*;
  32 import static java.math.BigDecimal.*;
  33 import java.util.Set;
  34 import java.util.EnumSet;
  35 
  36 public class AddTests {
  37 
  38     private static Set<RoundingMode> nonExactRoundingModes =
  39         EnumSet.complementOf(EnumSet.of(RoundingMode.UNNECESSARY));
  40 
  41     /**
  42      * Test for extreme value of scale and rounding precision that
  43      * could cause integer overflow in right-shift-into-sticky-bit
  44      * computations.
  45      */
  46     private static int extremaTests() {
  47         int failures = 0;
  48 
  49         failures += addWithoutException(valueOf(1, -Integer.MAX_VALUE),
  50                                         valueOf(2, Integer.MAX_VALUE), null);
  51         failures += addWithoutException(valueOf(1, -Integer.MAX_VALUE),
  52                                         valueOf(-2, Integer.MAX_VALUE), null);
  53         return failures;
  54     }
  55 
  56     /**
  57      * Print sum of b1 and b2; correct result will not throw an
  58      * exception.
  59      */
  60     private static int addWithoutException(BigDecimal b1, BigDecimal b2, MathContext mc) {
  61         if (mc == null)
  62             mc = new MathContext(2, RoundingMode.DOWN);
  63 
  64         try {
  65             BigDecimal sum = b1.add(b2, mc);
  66             printAddition(b1, b2, sum.toString());
  67             return 0;
  68         } catch(ArithmeticException ae) {
  69             printAddition(b1, b2, "Exception!");
  70             return 1;
  71         }
  72     }
  73 
  74     /**
  75      * Test combinations of operands that may meet the condensation
  76      * criteria when rounded to different precisions.
  77      */
  78     private static int roundingGradationTests() {
  79         int failures = 0;
  80 
  81         failures += roundAway(new BigDecimal("1234e100"),
  82                               new BigDecimal(   "1234e97"));
  83 
  84         failures += roundAway(new BigDecimal("1234e100"),
  85                               new BigDecimal(    "1234e96"));
  86 
  87         failures += roundAway(new BigDecimal("1234e100"),
  88                               new BigDecimal(     "1234e95"));
  89 
  90         failures += roundAway(new BigDecimal("1234e100"),
  91                               new BigDecimal(      "1234e94"));
  92 
  93         failures += roundAway(new BigDecimal("1234e100"),
  94                               new BigDecimal(       "1234e93"));
  95 
  96         failures += roundAway(new BigDecimal("1234e100"),
  97                               new BigDecimal(        "1234e92"));
  98 
  99         failures += roundAway(new BigDecimal("1234e100"),
 100                               new BigDecimal("1234e50"));
 101 
 102 
 103         failures += roundAway(new BigDecimal("1000e100"),
 104                               new BigDecimal(   "1234e97"));
 105 
 106         failures += roundAway(new BigDecimal("1000e100"),
 107                               new BigDecimal(    "1234e96"));
 108 
 109         failures += roundAway(new BigDecimal("1000e100"),
 110                               new BigDecimal(     "1234e95"));
 111 
 112         failures += roundAway(new BigDecimal("1000e100"),
 113                               new BigDecimal(      "1234e94"));
 114 
 115         failures += roundAway(new BigDecimal("1000e100"),
 116                               new BigDecimal(       "1234e93"));
 117 
 118         failures += roundAway(new BigDecimal("1000e100"),
 119                               new BigDecimal(        "1234e92"));
 120 
 121         failures += roundAway(new BigDecimal("1000e100"),
 122                               new BigDecimal("1234e50"));
 123 
 124 
 125 
 126         failures += roundAway(new BigDecimal("1999e100"),
 127                               new BigDecimal(   "1234e97"));
 128 
 129         failures += roundAway(new BigDecimal("1999e100"),
 130                               new BigDecimal(    "1234e96"));
 131 
 132         failures += roundAway(new BigDecimal("1999e100"),
 133                               new BigDecimal(     "1234e95"));
 134 
 135         failures += roundAway(new BigDecimal("1999e100"),
 136                               new BigDecimal(      "1234e94"));
 137 
 138         failures += roundAway(new BigDecimal("1999e100"),
 139                               new BigDecimal(       "1234e93"));
 140 
 141         failures += roundAway(new BigDecimal("1999e100"),
 142                               new BigDecimal(        "1234e92"));
 143 
 144         failures += roundAway(new BigDecimal("1999e100"),
 145                               new BigDecimal("1234e50"));
 146 
 147 
 148 
 149         failures += roundAway(new BigDecimal("9999e100"),
 150                               new BigDecimal(   "1234e97"));
 151 
 152         failures += roundAway(new BigDecimal("9999e100"),
 153                               new BigDecimal(    "1234e96"));
 154 
 155         failures += roundAway(new BigDecimal("9999e100"),
 156                               new BigDecimal(     "1234e95"));
 157 
 158         failures += roundAway(new BigDecimal("9999e100"),
 159                               new BigDecimal(      "1234e94"));
 160 
 161         failures += roundAway(new BigDecimal("9999e100"),
 162                               new BigDecimal(       "1234e93"));
 163 
 164         failures += roundAway(new BigDecimal("9999e100"),
 165                               new BigDecimal(        "1234e92"));
 166 
 167         failures += roundAway(new BigDecimal("9999e100"),
 168                               new BigDecimal("1234e50"));
 169 
 170         return failures;
 171     }
 172 
 173     private static void printAddition(BigDecimal b1, BigDecimal b2, String s) {
 174         System.out.println("" + b1+ "\t+\t" + b2 + "\t=\t" + s);
 175     }
 176 
 177     private static int roundAway(BigDecimal b1, BigDecimal b2) {
 178         int failures = 0;
 179 
 180         b1.precision();
 181         b2.precision();
 182 
 183         BigDecimal b1_negate = b1.negate();
 184         BigDecimal b2_negate = b2.negate();
 185 
 186         b1_negate.precision();
 187         b2_negate.precision();
 188 
 189         failures += roundAway1(b1,        b2);
 190         failures += roundAway1(b1,        b2_negate);
 191         failures += roundAway1(b1_negate, b2);
 192         failures += roundAway1(b1_negate, b2_negate);
 193 
 194         return failures;
 195     }
 196 
 197     private static int roundAway1(BigDecimal b1, BigDecimal b2) {
 198         int failures = 0;
 199         failures += roundAway0(b1, b2);
 200         failures += roundAway0(b2, b1);
 201         return failures;
 202     }
 203 
 204     /**
 205      * Compare b1.add(b2, mc) with b1.add(b2).round(mc) for a variety
 206      * of MathContexts.
 207      */
 208     private static int roundAway0(BigDecimal b1, BigDecimal b2) {
 209         int failures = 0;
 210         BigDecimal exactSum = b1.add(b2);
 211 
 212         for(int precision = 1 ; precision < exactSum.precision()+2; precision++) {
 213             for(RoundingMode rm : nonExactRoundingModes) {
 214                 MathContext mc = new MathContext(precision, rm);
 215                 BigDecimal roundedExactSum = exactSum.round(mc);
 216 
 217                 try {
 218                     BigDecimal sum = b1.add(b2, mc);
 219 
 220                     if (!roundedExactSum.equals(sum) ) {
 221                         failures++;
 222                         System.out.println("Exact sum " + exactSum +
 223                                            "\trounded by " + mc +
 224                                            "\texpected: " + roundedExactSum + " got: ");
 225                         printAddition(b1, b2, sum.toString());
 226                     }
 227 //                  else {
 228 //                      System.out.print(mc + "\t");
 229 //                      printAddition(b1, b2, sum.toString());
 230 //                  }
 231 
 232                 } catch (ArithmeticException ae) {
 233                     printAddition(b1, b2, "Exception!");
 234                     failures++;
 235                 }
 236             }
 237         }
 238 
 239         return failures;
 240     }
 241 
 242     /**
 243      * Verify calling the precision method should not change the
 244      * computed result.
 245      */
 246     private static int precisionConsistencyTest() {
 247         int failures = 0;
 248         MathContext mc = new MathContext(1,RoundingMode.DOWN);
 249         BigDecimal a = BigDecimal.valueOf(1999, -1); //value is equivalent to 19990
 250 
 251         BigDecimal sum1 = a.add(BigDecimal.ONE, mc);
 252         a.precision();
 253         BigDecimal sum2 = a.add(BigDecimal.ONE, mc);
 254 
 255         if (!sum1.equals(sum2)) {
 256             failures ++;
 257             System.out.println("Unequal sums after calling precision!");
 258             System.out.print("Before:\t");
 259             printAddition(a, BigDecimal.ONE, sum1.toString());
 260 
 261             System.out.print("After:\t");
 262             printAddition(a, BigDecimal.ONE, sum2.toString());
 263         }
 264 
 265         return failures;
 266     }
 267 
 268     public static void main(String argv[]) {
 269         int failures = 0;
 270 
 271         failures += extremaTests();
 272         failures += roundingGradationTests();
 273         failures += precisionConsistencyTest();
 274 
 275         if (failures > 0) {
 276             throw new RuntimeException("Incurred " + failures +
 277                                        " failures while testing rounding add.");
 278         }
 279     }
 280 }