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