almostEqualNormRelativeI function

bool almostEqualNormRelativeI (double a, double b, double diff, int decimalPlaces)

Compares two doubles and determines if they are equal to within the specified number of decimal places or not. If the numbers are very close to zero an absolute difference is compared, otherwise the relative difference is compared.

Implementation

bool almostEqualNormRelativeI(
    double a, double b, double diff, int decimalPlaces) {
  if (decimalPlaces < 0) {
    // Can't have a negative number of decimal places
    throw ArgumentError.value(
        decimalPlaces, "decimalPlaces", messages.argumentNotNegative);
  }

  // If A or B are a NAN, return false. NANs are equal to nothing,
  // not even themselves.
  if (a.isNaN || b.isNaN) {
    return false;
  }

  // If A or B are infinity (positive or negative) then
  // only return true if they are exactly equal to each other -
  // that is, if they are both infinities of the same sign.
  if (a.isInfinite || b.isInfinite) {
    return a == b;
  }

  // If both numbers are equal, get out now. This should remove the possibility
  // of both numbers being zero and any problems associated with that.
  if (a.compareTo(b) == 0) {
    return true;
  }

  // If one is almost zero, fall back to absolute equality
  if (a.abs() < doublePrecision || b.abs() < doublePrecision) {
    // The values are equal if the difference between the two numbers is smaller
    // than 10^(-numberOfDecimalPlaces). We divide by two so that we have half
    // the range on each side of the numbers, e.g. if decimalPlaces == 2,
    // then 0.01 will equal between 0.005 and 0.015, but not 0.02 and not 0.00
    return diff.abs() < pow(10, -decimalPlaces) / 2.0;
  }

  // If the magnitudes of the two numbers are equal to within one magnitude
  // the numbers could potentially be equal
  int magnitudeOfFirst = magnitude(a);
  int magnitudeOfSecond = magnitude(b);
  int magnitudeOfMax = max(magnitudeOfFirst, magnitudeOfSecond);
  if (magnitudeOfMax > (min(magnitudeOfFirst, magnitudeOfSecond) + 1)) {
    return false;
  }

  // The values are equal if the difference between the two numbers is smaller
  // than 10^(-numberOfDecimalPlaces). We divide by two so that we have half
  // the range on each side of the numbers, e.g. if decimalPlaces == 2, then
  // 0.01 will equal between 0.00995 and 0.01005, but not 0.0015 and not 0.0095
  return diff.abs() < pow(10, magnitudeOfMax - decimalPlaces) / 2.0;
}