У меня есть модульное тестирование, тестирование границы:Почему добавление double.epsilon к значению приводит к тому же значению, совершенно равному?
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void CreateExtent_InvalidTop_ShouldThrowArgumentOutOfRangeException()
{
var invalidTop = 90.0 + Double.Epsilon;
new Extent(invalidTop, 0.0, 0.0, 0.0);
}
public static readonly double MAX_LAT = 90.0;
public Extent(double top, double right, double bottom, double left)
{
if (top > GeoConstants.MAX_LAT)
throw new ArgumentOutOfRangeException("top"); // not hit
}
Я думал, что я просто наклонить 90.0 через край, добавив минимально возможный положительный двойной к нему, но теперь исключение не брошенные, ни малейшего представления Зачем?
При отладке, я вижу, что вершина входит как 90, когда она должна быть 90.00000000 .... что-то.
EDIT: я должен был подумать немного сложнее, 90+Double.Epsilon
потеряет свою резолюцию. Кажется, лучший способ пойти - это немного смещение.
РЕШЕНИЕ:
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void CreateExtent_InvalidTop_ShouldThrowArgumentOutOfRangeException()
{
var invalidTop = Utility.IncrementTiny(90); // 90.000000000000014
// var sameAsEpsilon = Utility.IncrementTiny(0);
new Extent(invalidTop, 0, 0, 0);
}
/// <summary>
/// Increment a double-precision number by the smallest amount possible
/// </summary>
/// <param name="number">double-precision number</param>
/// <returns>incremented number</returns>
public static double IncrementTiny(double number)
{
#region SANITY CHECKS
if (Double.IsNaN(number) || Double.IsInfinity(number))
throw new ArgumentOutOfRangeException("number");
#endregion
var bits = BitConverter.DoubleToInt64Bits(number);
// if negative then go opposite way
if (number > 0)
return BitConverter.Int64BitsToDouble(bits + 1);
else if (number < 0)
return BitConverter.Int64BitsToDouble(bits - 1);
else
return Double.Epsilon;
}
/// <summary>
/// Decrement a double-precision number by the smallest amount possible
/// </summary>
/// <param name="number">double-precision number</param>
/// <returns>decremented number</returns>
public static double DecrementTiny(double number)
{
#region SANITY CHECKS
if (Double.IsNaN(number) || Double.IsInfinity(number))
throw new ArgumentOutOfRangeException("number");
#endregion
var bits = BitConverter.DoubleToInt64Bits(number);
// if negative then go opposite way
if (number > 0)
return BitConverter.Int64BitsToDouble(bits - 1);
else if (number < 0)
return BitConverter.Int64BitsToDouble(bits + 1);
else
return 0 - Double.Epsilon;
}
Это делает работу.
Двойная точность - это неприятный бизнес, но при сравнении максимального отклонения между A и B это «Double.Epsilon», поэтому вы, вероятно, не набросились на него очень и очень небольшим отрывом. – jessehouwing
См. Http://stackoverflow.com/questions/2411392/double-epsilon-for-equality-greater-than-less-than-less-than-or-equal-to-gre – Habib
Интересная статья здесь: http://www.johndcook.com/blog/2012/01/05/double-epsilon-dbl_epsilon/ TL, DR - «Double.Epsilon» не так полезен, как вы думаете! » – AAT