001/*
002 * Copyright (C) 2020 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.math;
016
017import com.google.common.annotations.GwtIncompatible;
018import java.math.BigDecimal;
019import java.math.RoundingMode;
020
021/**
022 * A class for arithmetic on {@link BigDecimal} that is not covered by its built-in methods.
023 *
024 * @author Louis Wasserman
025 * @since 30.0
026 */
027@GwtIncompatible
028@ElementTypesAreNonnullByDefault
029public class BigDecimalMath {
030  private BigDecimalMath() {}
031
032  /**
033   * Returns {@code x}, rounded to a {@code double} with the specified rounding mode. If {@code x}
034   * is precisely representable as a {@code double}, its {@code double} value will be returned;
035   * otherwise, the rounding will choose between the two nearest representable values with {@code
036   * mode}.
037   *
038   * <p>For the case of {@link RoundingMode#HALF_DOWN}, {@code HALF_UP}, and {@code HALF_EVEN},
039   * infinite {@code double} values are considered infinitely far away. For example, 2^2000 is not
040   * representable as a double, but {@code roundToDouble(BigDecimal.valueOf(2).pow(2000), HALF_UP)}
041   * will return {@code Double.MAX_VALUE}, not {@code Double.POSITIVE_INFINITY}.
042   *
043   * <p>For the case of {@link RoundingMode#HALF_EVEN}, this implementation uses the IEEE 754
044   * default rounding mode: if the two nearest representable values are equally near, the one with
045   * the least significant bit zero is chosen. (In such cases, both of the nearest representable
046   * values are even integers; this method returns the one that is a multiple of a greater power of
047   * two.)
048   *
049   * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
050   *     is not precisely representable as a {@code double}
051   * @since 30.0
052   */
053  public static double roundToDouble(BigDecimal x, RoundingMode mode) {
054    return BigDecimalToDoubleRounder.INSTANCE.roundToDouble(x, mode);
055  }
056
057  private static class BigDecimalToDoubleRounder extends ToDoubleRounder<BigDecimal> {
058    static final BigDecimalToDoubleRounder INSTANCE = new BigDecimalToDoubleRounder();
059
060    private BigDecimalToDoubleRounder() {}
061
062    @Override
063    double roundToDoubleArbitrarily(BigDecimal bigDecimal) {
064      return bigDecimal.doubleValue();
065    }
066
067    @Override
068    int sign(BigDecimal bigDecimal) {
069      return bigDecimal.signum();
070    }
071
072    @Override
073    BigDecimal toX(double d, RoundingMode mode) {
074      return new BigDecimal(d);
075    }
076
077    @Override
078    BigDecimal minus(BigDecimal a, BigDecimal b) {
079      return a.subtract(b);
080    }
081  }
082}