为什么添加double.epsilon到一个值会导致相同的值,完全相等? [英] Why does adding double.epsilon to a value result in the same value, perfectly equal?

查看:166
本文介绍了为什么添加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(最佳); // not hit
}

我以为我只是把90.0提升到边缘通过添加最小可能的正双倍,但现在异常没有抛出,任何想法为什么?



调试时,我看到顶部进入90,当它应该是90.00000000 ....一些东西。



编辑:
我应该有点更难, 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>
///以最小的数量增加双精度数
///< / 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))
抛出新的ArgumentOutOfRangeException(number);
#endregion

var bits = BitConverter.DoubleToInt64Bits(number);

//如果为负,则相反方式
if(number> 0)
返回BitConverter.Int64BitsToDouble(bits + 1);
else if(number< 0)
return BitConverter.Int64BitsToDouble(bits-1);
else
return Double.Epsilon;
}

///< summary>
///以最小的数量减去双精度数
///< / summary>
///< param name =number> double-precision number< / param>
///< returns>递减的数字< / returns>
public static double DecrementTiny(double number)
{
#region SANITY CHECKS
if(Double.IsNaN(number)|| Double.IsInfinity(number))
抛出新的ArgumentOutOfRangeException(number);
#endregion

var bits = BitConverter.DoubleToInt64Bits(number);

//如果否定,则相反方式
if(number> 0)
返回BitConverter.Int64BitsToDouble(bits-1);
else if(number< 0)
return BitConverter.Int64BitsToDouble(bits + 1);
else
返回0 - Double.Epsilon;
}

这样做。

解决方案

根据 <$ c的文档$ c> Double.Epsilon


Epsilon属性的值反映出最小的
Double 在数值操作或比较中有重要价值的值
Double 实例是零


(重点是我的)



将其添加到90.0不会产生90.0之后的下一个最小值,这只会产生90.0。


I have a unit test, testing boundaries:

[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
}

I thought I'd just tip the 90.0 over the edge by adding the minimum possible positive double to it, but now the exception is not thrown, any idea why?

When debugging, I see top as coming in as 90, when it should be 90.00000000.... something.

EDIT: I should have thought a bit harder, 90+Double.Epsilon will lose its resolution. Seems the best way to go is do some bit shifting.

SOLUTION:

[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;
}

This does the job.

解决方案

Per the documentation of Double.Epsilon:

The value of the Epsilon property reflects the smallest positive Double value that is significant in numeric operations or comparisons when the value of the Double instance is zero.

(Emphasis mine.)

Adding it to 90.0 does not produce "the next smallest value after 90.0", this just yields 90.0 again.

这篇关于为什么添加double.epsilon到一个值会导致相同的值,完全相等?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆