Coverage Summary for Class: ToDoubleRounder (com.google.common.math)

Class Method, % Line, %
ToDoubleRounder 0% (0/2) 0% (0/62)
ToDoubleRounder$1 0% (0/1) 0% (0/1)
Total 0% (0/3) 0% (0/63)


1 /* 2  * Copyright (C) 2020 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.math; 16  17 import static com.google.common.base.Preconditions.checkNotNull; 18 import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary; 19  20 import com.google.common.annotations.GwtIncompatible; 21 import java.math.RoundingMode; 22  23 /** 24  * Helper type to implement rounding {@code X} to a representable {@code double} value according to 25  * a {@link RoundingMode}. 26  */ 27 @GwtIncompatible 28 @ElementTypesAreNonnullByDefault 29 abstract class ToDoubleRounder<X extends Number & Comparable<X>> { 30  /** 31  * Returns x rounded to either the greatest double less than or equal to the precise value of x, 32  * or the least double greater than or equal to the precise value of x. 33  */ 34  abstract double roundToDoubleArbitrarily(X x); 35  36  /** Returns the sign of x: either -1, 0, or 1. */ 37  abstract int sign(X x); 38  39  /** Returns d's value as an X, rounded with the specified mode. */ 40  abstract X toX(double d, RoundingMode mode); 41  42  /** Returns a - b, guaranteed that both arguments are nonnegative. */ 43  abstract X minus(X a, X b); 44  45  /** Rounds {@code x} to a {@code double}. */ 46  final double roundToDouble(X x, RoundingMode mode) { 47  checkNotNull(x, "x"); 48  checkNotNull(mode, "mode"); 49  double roundArbitrarily = roundToDoubleArbitrarily(x); 50  if (Double.isInfinite(roundArbitrarily)) { 51  switch (mode) { 52  case DOWN: 53  case HALF_EVEN: 54  case HALF_DOWN: 55  case HALF_UP: 56  return Double.MAX_VALUE * sign(x); 57  case FLOOR: 58  return (roundArbitrarily == Double.POSITIVE_INFINITY) 59  ? Double.MAX_VALUE 60  : Double.NEGATIVE_INFINITY; 61  case CEILING: 62  return (roundArbitrarily == Double.POSITIVE_INFINITY) 63  ? Double.POSITIVE_INFINITY 64  : -Double.MAX_VALUE; 65  case UP: 66  return roundArbitrarily; 67  case UNNECESSARY: 68  throw new ArithmeticException(x + " cannot be represented precisely as a double"); 69  } 70  } 71  X roundArbitrarilyAsX = toX(roundArbitrarily, RoundingMode.UNNECESSARY); 72  int cmpXToRoundArbitrarily = x.compareTo(roundArbitrarilyAsX); 73  switch (mode) { 74  case UNNECESSARY: 75  checkRoundingUnnecessary(cmpXToRoundArbitrarily == 0); 76  return roundArbitrarily; 77  case FLOOR: 78  return (cmpXToRoundArbitrarily >= 0) 79  ? roundArbitrarily 80  : DoubleUtils.nextDown(roundArbitrarily); 81  case CEILING: 82  return (cmpXToRoundArbitrarily <= 0) ? roundArbitrarily : Math.nextUp(roundArbitrarily); 83  case DOWN: 84  if (sign(x) >= 0) { 85  return (cmpXToRoundArbitrarily >= 0) 86  ? roundArbitrarily 87  : DoubleUtils.nextDown(roundArbitrarily); 88  } else { 89  return (cmpXToRoundArbitrarily <= 0) ? roundArbitrarily : Math.nextUp(roundArbitrarily); 90  } 91  case UP: 92  if (sign(x) >= 0) { 93  return (cmpXToRoundArbitrarily <= 0) ? roundArbitrarily : Math.nextUp(roundArbitrarily); 94  } else { 95  return (cmpXToRoundArbitrarily >= 0) 96  ? roundArbitrarily 97  : DoubleUtils.nextDown(roundArbitrarily); 98  } 99  case HALF_DOWN: 100  case HALF_UP: 101  case HALF_EVEN: 102  { 103  X roundFloor; 104  double roundFloorAsDouble; 105  X roundCeiling; 106  double roundCeilingAsDouble; 107  108  if (cmpXToRoundArbitrarily >= 0) { 109  roundFloorAsDouble = roundArbitrarily; 110  roundFloor = roundArbitrarilyAsX; 111  roundCeilingAsDouble = Math.nextUp(roundArbitrarily); 112  if (roundCeilingAsDouble == Double.POSITIVE_INFINITY) { 113  return roundFloorAsDouble; 114  } 115  roundCeiling = toX(roundCeilingAsDouble, RoundingMode.CEILING); 116  } else { 117  roundCeilingAsDouble = roundArbitrarily; 118  roundCeiling = roundArbitrarilyAsX; 119  roundFloorAsDouble = DoubleUtils.nextDown(roundArbitrarily); 120  if (roundFloorAsDouble == Double.NEGATIVE_INFINITY) { 121  return roundCeilingAsDouble; 122  } 123  roundFloor = toX(roundFloorAsDouble, RoundingMode.FLOOR); 124  } 125  126  X deltaToFloor = minus(x, roundFloor); 127  X deltaToCeiling = minus(roundCeiling, x); 128  int diff = deltaToFloor.compareTo(deltaToCeiling); 129  if (diff < 0) { // closer to floor 130  return roundFloorAsDouble; 131  } else if (diff > 0) { // closer to ceiling 132  return roundCeilingAsDouble; 133  } 134  // halfway between the representable values; do the half-whatever logic 135  switch (mode) { 136  case HALF_EVEN: 137  // roundFloorAsDouble and roundCeilingAsDouble are neighbors, so precisely 138  // one of them should have an even long representation 139  return ((Double.doubleToRawLongBits(roundFloorAsDouble) & 1L) == 0) 140  ? roundFloorAsDouble 141  : roundCeilingAsDouble; 142  case HALF_DOWN: 143  return (sign(x) >= 0) ? roundFloorAsDouble : roundCeilingAsDouble; 144  case HALF_UP: 145  return (sign(x) >= 0) ? roundCeilingAsDouble : roundFloorAsDouble; 146  default: 147  throw new AssertionError("impossible"); 148  } 149  } 150  } 151  throw new AssertionError("impossible"); 152  } 153 }