rangeOfMatchingNumbers function

Tuple2<int, int> rangeOfMatchingNumbers (double value, double relativeDifference)

Determines the range of ulps that will match the specified value with the given tolerance.

Returns tuple with the number of ULPS between the value and the value - relativeDifference as first, and the number of ULPS between the value and the value + relativeDifference as second value. Throws ArgumentError if relativeDifference is smaller than zero. Throws ArgumentError if value is double.infinity or double.negativeInfinity. Throws ArgumentError if value is double.nan.

Implementation

Tuple2<int, int> rangeOfMatchingNumbers(
    double value, double relativeDifference) {
  // Make sure the relative is non-negative
  if (relativeDifference < 0) {
    throw ArgumentError.value(
        relativeDifference, 'relativeDifference', messages.argumentNotNegative);
  }

  // If the value is infinity (positive or negative) then
  // we can't determine the range.
  if (value.isInfinite) {
    throw ArgumentError('Value is infinite.');
  }

  // If the value is a NaN then we can't determine the range.
  if (value.isNaN) {
    throw ArgumentError('Value is not a number.');
  }

  // If the value is zero (0.0) then we can't calculate the relative difference
  // so return the ulps counts for the difference.
  if (value.compareTo(0.0) == 0) {
    var bytes = ByteData(8);
    bytes.setFloat64(0, relativeDifference);
    var v = bytes.getInt64(0);
    return Tuple2<int, int>(v, v);
  }

  // Calculate the ulps for the maximum and minimum values
  // Note that these can overflow
  int max = asDirectionalInt64(value + (relativeDifference * value.abs()));
  int min = asDirectionalInt64(value - (relativeDifference * value.abs()));

  // Calculate the ulps from the value
  int intValue = asDirectionalInt64(value);

  // Determine the ranges
  return Tuple2<int, int>((intValue - min).abs(), (max - intValue).abs());
}