| /* |
| * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * @test |
| * @bug 4902952 4905407 4916149 |
| * @summary Tests that the scale of zero is propagated properly and has the proper effect. |
| * @author Joseph D. Darcy |
| */ |
| |
| import java.math.*; |
| import java.util.*; |
| |
| public class ZeroScalingTests { |
| |
| static MathContext longEnough = new MathContext(50, RoundingMode.UNNECESSARY); |
| |
| static BigDecimal[] zeros = new BigDecimal[23]; |
| static { |
| for(int i = 0; i < 21; i++) { |
| zeros[i] = new BigDecimal(BigInteger.ZERO, i-10); |
| } |
| zeros[21] = new BigDecimal(BigInteger.ZERO, Integer.MIN_VALUE); |
| zeros[22] = new BigDecimal(BigInteger.ZERO, Integer.MAX_VALUE); |
| } |
| |
| static BigDecimal element = BigDecimal.valueOf(100, -2); |
| |
| static MathContext contexts[] = { |
| new MathContext(0, RoundingMode.UNNECESSARY), |
| new MathContext(100, RoundingMode.UNNECESSARY), |
| new MathContext(5, RoundingMode.UNNECESSARY), |
| new MathContext(4, RoundingMode.UNNECESSARY), |
| new MathContext(3, RoundingMode.UNNECESSARY), |
| new MathContext(2, RoundingMode.UNNECESSARY), |
| new MathContext(1, RoundingMode.UNNECESSARY), |
| }; |
| |
| |
| static int addTests() { |
| int failures = 0; |
| |
| for(BigDecimal zero1: zeros) { |
| for(BigDecimal zero2: zeros) { |
| BigDecimal expected = new BigDecimal(BigInteger.ZERO, |
| Math.max(zero1.scale(), zero2.scale())); |
| BigDecimal result; |
| |
| if(! (result=zero1.add(zero2)).equals(expected) ) { |
| failures++; |
| System.err.println("For classic exact add, expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| if(! (result=zero1.add(zero2, MathContext.UNLIMITED)).equals(expected) ) { |
| failures++; |
| System.err.println("For UNLIMITED math context add," + |
| " expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| if(! (result=zero1.add(zero2, longEnough)).equals(expected) ) { |
| failures++; |
| System.err.println("For longEnough math context add," + |
| " expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| } |
| } |
| |
| // Test effect of adding zero to a nonzero value. |
| for (MathContext mc: contexts) { |
| for (BigDecimal zero: zeros) { |
| if (Math.abs((long)zero.scale()) < 100 ) { |
| |
| int preferredScale = Math.max(zero.scale(), element.scale()); |
| if (mc.getPrecision() != 0) { |
| if (preferredScale < -4 ) |
| preferredScale = -4; |
| else if (preferredScale > -(5 - mc.getPrecision())) { |
| preferredScale = -(5 - mc.getPrecision()); |
| } |
| } |
| |
| |
| /* |
| System.err.println("\n " + element + " +\t" + zero + " =\t" + result); |
| |
| System.err.println("scales" + element.scale() + " \t" + zero.scale() + |
| " \t " + result.scale() + "\t precison = " + mc.getPrecision()); |
| System.err.println("expected scale = " + preferredScale); |
| */ |
| |
| BigDecimal result = element.add(zero, mc); |
| if (result.scale() != preferredScale || |
| result.compareTo(element) != 0) { |
| failures++; |
| System.err.println("Expected scale " + preferredScale + |
| " result scale was " + result.scale() + |
| " ; value was " + result); |
| } |
| |
| result = zero.add(element, mc); |
| if (result.scale() != preferredScale || |
| result.compareTo(element) != 0) { |
| failures++; |
| System.err.println("Expected scale " + preferredScale + |
| " result scale was " + result.scale() + |
| " ; value was " + result); |
| } |
| |
| result = element.negate().add(zero, mc); |
| if (result.scale() != preferredScale || |
| result.compareTo(element.negate()) != 0) { |
| failures++; |
| System.err.println("Expected scale " + preferredScale + |
| " result scale was " + result.scale() + |
| " ; value was " + result); |
| } |
| |
| result = zero.add(element.negate(), mc); |
| if (result.scale() != preferredScale || |
| result.compareTo(element.negate()) != 0) { |
| failures++; |
| System.err.println("Expected scale " + preferredScale + |
| " result scale was " + result.scale() + |
| " ; value was " + result); |
| } |
| |
| } |
| } |
| } |
| |
| return failures; |
| } |
| |
| static int subtractTests() { |
| int failures = 0; |
| |
| for(BigDecimal zero1: zeros) { |
| for(BigDecimal zero2: zeros) { |
| BigDecimal expected = new BigDecimal(BigInteger.ZERO, |
| Math.max(zero1.scale(), zero2.scale())); |
| BigDecimal result; |
| |
| if(! (result=zero1.subtract(zero2)).equals(expected) ) { |
| failures++; |
| System.err.println("For classic exact subtract, expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| if(! (result=zero1.subtract(zero2, MathContext.UNLIMITED)).equals(expected) ) { |
| failures++; |
| System.err.println("For UNLIMITED math context subtract," + |
| " expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| if(! (result=zero1.subtract(zero2, longEnough)).equals(expected) ) { |
| failures++; |
| System.err.println("For longEnough math context subtract," + |
| " expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| } |
| } |
| |
| |
| // Test effect of adding zero to a nonzero value. |
| for (MathContext mc: contexts) { |
| for (BigDecimal zero: zeros) { |
| if (Math.abs((long)zero.scale()) < 100 ) { |
| |
| int preferredScale = Math.max(zero.scale(), element.scale()); |
| if (mc.getPrecision() != 0) { |
| if (preferredScale < -4 ) |
| preferredScale = -4; |
| else if (preferredScale > -(5 - mc.getPrecision())) { |
| preferredScale = -(5 - mc.getPrecision()); |
| } |
| } |
| |
| |
| /* |
| System.err.println("\n " + element + " +\t" + zero + " =\t" + result); |
| |
| System.err.println("scales" + element.scale() + " \t" + zero.scale() + |
| " \t " + result.scale() + "\t precison = " + mc.getPrecision()); |
| System.err.println("expected scale = " + preferredScale); |
| */ |
| |
| BigDecimal result = element.subtract(zero, mc); |
| if (result.scale() != preferredScale || |
| result.compareTo(element) != 0) { |
| failures++; |
| System.err.println("Expected scale " + preferredScale + |
| " result scale was " + result.scale() + |
| " ; value was " + result); |
| } |
| |
| result = zero.subtract(element, mc); |
| if (result.scale() != preferredScale || |
| result.compareTo(element.negate()) != 0) { |
| failures++; |
| System.err.println("Expected scale " + preferredScale + |
| " result scale was " + result.scale() + |
| " ; value was " + result); |
| } |
| |
| result = element.negate().subtract(zero, mc); |
| if (result.scale() != preferredScale || |
| result.compareTo(element.negate()) != 0) { |
| failures++; |
| System.err.println("Expected scale " + preferredScale + |
| " result scale was " + result.scale() + |
| " ; value was " + result); |
| } |
| |
| result = zero.subtract(element.negate(), mc); |
| if (result.scale() != preferredScale || |
| result.compareTo(element) != 0) { |
| failures++; |
| System.err.println("Expected scale " + preferredScale + |
| " result scale was " + result.scale() + |
| " ; value was " + result); |
| } |
| |
| } |
| } |
| } |
| |
| return failures; |
| } |
| |
| static int multiplyTests() { |
| int failures = 0; |
| |
| BigDecimal ones[] = { |
| BigDecimal.valueOf(1, 0), |
| BigDecimal.valueOf(10, 1), |
| BigDecimal.valueOf(1000, 3), |
| BigDecimal.valueOf(100000000, 8), |
| }; |
| |
| List<BigDecimal> values = new LinkedList<BigDecimal>(); |
| values.addAll(Arrays.asList(zeros)); |
| values.addAll(Arrays.asList(ones)); |
| |
| for(BigDecimal zero1: zeros) { |
| for(BigDecimal value: values) { |
| BigDecimal expected = new BigDecimal(BigInteger.ZERO, |
| (int)Math.min(Math.max((long)zero1.scale()+value.scale(), |
| Integer.MIN_VALUE ), |
| Integer.MAX_VALUE ) ); |
| BigDecimal result; |
| |
| if(! (result=zero1.multiply(value)).equals(expected) ) { |
| failures++; |
| System.err.println("For classic exact multiply, expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| if(! (result=zero1.multiply(value, MathContext.UNLIMITED)).equals(expected) ) { |
| failures++; |
| System.err.println("For UNLIMITED math context multiply," + |
| " expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| if(! (result=zero1.multiply(value, longEnough)).equals(expected) ) { |
| failures++; |
| System.err.println("For longEnough math context multiply," + |
| " expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| } |
| } |
| |
| return failures; |
| } |
| |
| static int divideTests() { |
| int failures = 0; |
| |
| BigDecimal [] ones = { |
| BigDecimal.valueOf(1, 0), |
| BigDecimal.valueOf(10, -1), |
| BigDecimal.valueOf(100, -2), |
| BigDecimal.valueOf(1000, -3), |
| BigDecimal.valueOf(1000000, -5), |
| }; |
| |
| for(BigDecimal one: ones) { |
| for(BigDecimal zero: zeros) { |
| BigDecimal expected = new BigDecimal(BigInteger.ZERO, |
| (int)Math.min(Math.max((long)zero.scale() - one.scale(), |
| Integer.MIN_VALUE ), |
| Integer.MAX_VALUE ) ); |
| BigDecimal result; |
| |
| if(! (result=zero.divide(one)).equals(expected) ) { |
| failures++; |
| System.err.println("For classic exact divide, expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| if(! (result=zero.divide(one, MathContext.UNLIMITED)).equals(expected) ) { |
| failures++; |
| System.err.println("For UNLIMITED math context divide," + |
| " expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| if(! (result=zero.divide(one, longEnough)).equals(expected) ) { |
| failures++; |
| System.err.println("For longEnough math context divide," + |
| " expected scale of " + |
| expected.scale() + "; got " + |
| result.scale() + "."); |
| } |
| |
| } |
| } |
| |
| return failures; |
| } |
| |
| static int setScaleTests() { |
| int failures = 0; |
| |
| int scales[] = { |
| Integer.MIN_VALUE, |
| Integer.MIN_VALUE+1, |
| -10000000, |
| -3, |
| -2, |
| -1, |
| 0, |
| 1, |
| 2, |
| 3, |
| 10, |
| 10000000, |
| Integer.MAX_VALUE-1, |
| Integer.MAX_VALUE |
| }; |
| |
| for(BigDecimal zero: zeros) { |
| for(int scale: scales) { |
| try { |
| BigDecimal bd = zero.setScale(scale); |
| } |
| catch (ArithmeticException e) { |
| failures++; |
| System.err.println("Exception when trying to set a scale of " + scale + |
| " on " + zero); |
| } |
| } |
| } |
| |
| return failures; |
| } |
| |
| static int toEngineeringStringTests() { |
| int failures = 0; |
| |
| String [][] testCases = { |
| {"0E+10", "0.00E+12"}, |
| {"0E+9", "0E+9"}, |
| {"0E+8", "0.0E+9"}, |
| {"0E+7", "0.00E+9"}, |
| |
| {"0E-10", "0.0E-9"}, |
| {"0E-9", "0E-9"}, |
| {"0E-8", "0.00E-6"}, |
| {"0E-7", "0.0E-6"}, |
| }; |
| |
| for(String[] testCase: testCases) { |
| BigDecimal bd = new BigDecimal(testCase[0]); |
| String result = bd.toEngineeringString(); |
| |
| if (!result.equals(testCase[1]) || |
| !bd.equals(new BigDecimal(result))) { |
| failures++; |
| System.err.println("From input ``" + testCase[0] + ",'' " + |
| " bad engineering string output ``" + result + |
| "''; expected ``" + testCase[1] + ".''"); |
| } |
| |
| } |
| |
| return failures; |
| } |
| |
| static int ulpTests() { |
| int failures = 0; |
| |
| for(BigDecimal zero: zeros) { |
| BigDecimal result; |
| BigDecimal expected = BigDecimal.valueOf(1, zero.scale()); |
| |
| if (! (result=zero.ulp()).equals(expected) ) { |
| failures++; |
| System.err.println("Unexpected ulp value for zero value " + |
| zero + "; expected " + expected + |
| ", got " + result); |
| } |
| } |
| |
| return failures; |
| } |
| |
| public static void main(String argv[]) { |
| int failures = 0; |
| |
| failures += addTests(); |
| failures += subtractTests(); |
| failures += multiplyTests(); |
| failures += divideTests(); |
| failures += setScaleTests(); |
| failures += toEngineeringStringTests(); |
| failures += ulpTests(); |
| |
| if (failures > 0 ) { |
| throw new RuntimeException("Incurred " + failures + " failures" + |
| " testing the preservation of zero scales."); |
| } |
| } |
| } |