简体   繁体   English

C#值比较

[英]C# Value Comparison

I have compared two variable of different types with same values, 我比较了两个具有相同值的不同类型的变量,

int i = 100;
short s = (short)100;

if (s == i)
{
   return "Equals";
}
else
{
  return "Not Equals";
}

float f = 100.5f;
double d = 100.5d;

if (d == f)
{
   return "Equals";
}
else
{
  return "Not Equals";
}

The First comparison output is "Equal" and Second Comparison output is " Not Equal" 第一个比较输出为“等于”,第二个比较输出为“不等于”

My Question is How same value for short & int are Equal, If it is Equals then why not same value for float and double are equal. 我的问题是short和int的相同值如何相等,如果等于,那么为什么float和double的相同值不相等。

This is not only for float and double, If we compared decimal it will show compiler error. 这不仅适用于浮点数和双精度数,如果我们比较十进制数,它将显示编译器错误。

The int and short are equal because "upgrading" a short to an int will not change its value. intshort相等,因为将short提升为int不会改变其值。 The reason the float and double are not equal is because their values differ slightly. floatdouble不相等的原因是因为它们的值略有不同。 Equal comparison between double s and float s will give these kinds of problems. doublefloatEqual比较会产生这些问题。

The Microsoft .NET Framework source has a nice utility that is specifically to use for these kinds of issues. Microsoft .NET Framework源代码有一个很好的实用程序,专门用于解决此类问题。 These utilities try to allow you to do equal (or near equal) comparison on float s and double s. 这些实用程序试图让您对float s和double s进行相等(或近似相等)比较。

//---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: DoubleUtil.cs 
//
// Description: This file contains the implementation of DoubleUtil, which 
//              provides "fuzzy" comparison functionality for doubles and 
//              double-based classes and structs in our code.
// 
// History:
//  04/28/2003 : [....] - Created
//  05/20/2003 : [....] - Moved it to Shared, so Base, Core and Framework can all share.
// 
//---------------------------------------------------------------------------

using System; 
using System.Windows;
using System.Runtime.InteropServices; 

namespace Util
{ 
    public static class DoubleUtil 
    {
        // Const values come from sdk\inc\crt\float.h
        internal const double DBL_EPSILON  =   2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */
        internal const float  FLT_MIN      =   1.175494351e-38F; /* Number close to zero, where float.MinValue is -float.MaxValue */ 

        /// <summary> 
        /// AreClose - Returns whether or not two doubles are "close".  That is, whether or 
        /// not they are within epsilon of each other.  Note that this epsilon is proportional
        /// to the numbers themselves to that AreClose survives scalar multiplication. 
        /// There are plenty of ways for this to return false even for numbers which
        /// are theoretically identical, so no code calling this should fail to work if this
        /// returns false.  This is important enough to repeat:
        /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be 
        /// used for optimizations *only*.
        /// </summary> 
        /// <returns> 
        /// bool - the result of the AreClose comparision.
        /// </returns> 
        /// <param name="value1"> The first double to compare. </param>
        /// <param name="value2"> The second double to compare. </param>
        public static bool AreClose(double value1, double value2)
        { 
            //in case they are Infinities (then epsilon check does not work)
            if(value1 == value2) return true; 
            // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON 
            double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
            double delta = value1 - value2; 
            return(-eps < delta) && (eps > delta);
        }

        /// <summary> 
        /// LessThan - Returns whether or not the first double is less than the second double.
        /// That is, whether or not the first is strictly less than *and* not within epsilon of 
        /// the other number.  Note that this epsilon is proportional to the numbers themselves 
        /// to that AreClose survives scalar multiplication.  Note,
        /// There are plenty of ways for this to return false even for numbers which 
        /// are theoretically identical, so no code calling this should fail to work if this
        /// returns false.  This is important enough to repeat:
        /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be
        /// used for optimizations *only*. 
        /// </summary>
        /// <returns> 
        /// bool - the result of the LessThan comparision. 
        /// </returns>
        /// <param name="value1"> The first double to compare. </param> 
        /// <param name="value2"> The second double to compare. </param>
        public static bool LessThan(double value1, double value2)
        {
            return (value1 < value2) && !AreClose(value1, value2); 
        }


        /// <summary>
        /// GreaterThan - Returns whether or not the first double is greater than the second double. 
        /// That is, whether or not the first is strictly greater than *and* not within epsilon of
        /// the other number.  Note that this epsilon is proportional to the numbers themselves
        /// to that AreClose survives scalar multiplication.  Note,
        /// There are plenty of ways for this to return false even for numbers which 
        /// are theoretically identical, so no code calling this should fail to work if this
        /// returns false.  This is important enough to repeat: 
        /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be 
        /// used for optimizations *only*.
        /// </summary> 
        /// <returns>
        /// bool - the result of the GreaterThan comparision.
        /// </returns>
        /// <param name="value1"> The first double to compare. </param> 
        /// <param name="value2"> The second double to compare. </param>
        public static bool GreaterThan(double value1, double value2) 
        { 
            return (value1 > value2) && !AreClose(value1, value2);
        } 

        /// <summary>
        /// LessThanOrClose - Returns whether or not the first double is less than or close to
        /// the second double.  That is, whether or not the first is strictly less than or within 
        /// epsilon of the other number.  Note that this epsilon is proportional to the numbers
        /// themselves to that AreClose survives scalar multiplication.  Note, 
        /// There are plenty of ways for this to return false even for numbers which 
        /// are theoretically identical, so no code calling this should fail to work if this
        /// returns false.  This is important enough to repeat: 
        /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be
        /// used for optimizations *only*.
        /// </summary>
        /// <returns> 
        /// bool - the result of the LessThanOrClose comparision.
        /// </returns> 
        /// <param name="value1"> The first double to compare. </param> 
        /// <param name="value2"> The second double to compare. </param>
        public static bool LessThanOrClose(double value1, double value2) 
        {
            return (value1 < value2) || AreClose(value1, value2);
        }

        /// <summary>
        /// GreaterThanOrClose - Returns whether or not the first double is greater than or close to 
        /// the second double.  That is, whether or not the first is strictly greater than or within 
        /// epsilon of the other number.  Note that this epsilon is proportional to the numbers
        /// themselves to that AreClose survives scalar multiplication.  Note, 
        /// There are plenty of ways for this to return false even for numbers which
        /// are theoretically identical, so no code calling this should fail to work if this
        /// returns false.  This is important enough to repeat:
        /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be 
        /// used for optimizations *only*.
        /// </summary> 
        /// <returns> 
        /// bool - the result of the GreaterThanOrClose comparision.
        /// </returns> 
        /// <param name="value1"> The first double to compare. </param>
        /// <param name="value2"> The second double to compare. </param>
        public static bool GreaterThanOrClose(double value1, double value2)
        { 
            return (value1 > value2) || AreClose(value1, value2);
        } 

        /// <summary>
        /// IsOne - Returns whether or not the double is "close" to 1.  Same as AreClose(double, 1), 
        /// but this is faster.
        /// </summary>
        /// <returns>
        /// bool - the result of the AreClose comparision. 
        /// </returns>
        /// <param name="value"> The double to compare to 1. </param> 
        public static bool IsOne(double value) 
        {
            return Math.Abs(value-1.0) < 10.0 * DBL_EPSILON; 
        }

        /// <summary>
        /// IsZero - Returns whether or not the double is "close" to 0.  Same as AreClose(double, 0), 
        /// but this is faster.
        /// </summary> 
        /// <returns> 
        /// bool - the result of the AreClose comparision.
        /// </returns> 
        /// <param name="value"> The double to compare to 0. </param>
        public static bool IsZero(double value)
        {
            return Math.Abs(value) < 10.0 * DBL_EPSILON; 
        }

        // The Point, Size, Rect and Matrix class have moved to WinCorLib.  However, we provide 
        // internal AreClose methods for our own use here.

        /// <summary>
        /// Compares two points for fuzzy equality.  This function
        /// helps compensate for the fact that double values can
        /// acquire error when operated upon 
        /// </summary>
        /// <param name='point1'>The first point to compare</param> 
        /// <param name='point2'>The second point to compare</param> 
        /// <returns>Whether or not the two points are equal</returns>
        public static bool AreClose(Point point1, Point point2) 
        {
            return DoubleUtil.AreClose(point1.X, point2.X) &&
            DoubleUtil.AreClose(point1.Y, point2.Y);
        } 

        /// <summary> 
        /// Compares two Size instances for fuzzy equality.  This function 
        /// helps compensate for the fact that double values can
        /// acquire error when operated upon 
        /// </summary>
        /// <param name='size1'>The first size to compare</param>
        /// <param name='size2'>The second size to compare</param>
        /// <returns>Whether or not the two Size instances are equal</returns> 
        public static bool AreClose(Size size1, Size size2)
        { 
            return DoubleUtil.AreClose(size1.Width, size2.Width) && 
                   DoubleUtil.AreClose(size1.Height, size2.Height);
        } 

        /// <summary>
        /// Compares two Vector instances for fuzzy equality.  This function
        /// helps compensate for the fact that double values can 
        /// acquire error when operated upon
        /// </summary> 
        /// <param name='vector1'>The first Vector to compare</param> 
        /// <param name='vector2'>The second Vector to compare</param>
        /// <returns>Whether or not the two Vector instances are equal</returns> 
        public static bool AreClose(System.Windows.Vector vector1, System.Windows.Vector vector2)
        {
            return DoubleUtil.AreClose(vector1.X, vector2.X) &&
                   DoubleUtil.AreClose(vector1.Y, vector2.Y); 
        }

        /// <summary> 
        /// Compares two rectangles for fuzzy equality.  This function
        /// helps compensate for the fact that double values can 
        /// acquire error when operated upon
        /// </summary>
        /// <param name='rect1'>The first rectangle to compare</param>
        /// <param name='rect2'>The second rectangle to compare</param> 
        /// <returns>Whether or not the two rectangles are equal</returns>
        public static bool AreClose(Rect rect1, Rect rect2) 
        { 
            // If they're both empty, don't bother with the double logic.
            if (rect1.IsEmpty) 
            {
                return rect2.IsEmpty;
            }

            // At this point, rect1 isn't empty, so the first thing we can test is
            // rect2.IsEmpty, followed by property-wise compares. 

            return (!rect2.IsEmpty) &&
                DoubleUtil.AreClose(rect1.X, rect2.X) && 
                DoubleUtil.AreClose(rect1.Y, rect2.Y) &&
                DoubleUtil.AreClose(rect1.Height, rect2.Height) &&
                DoubleUtil.AreClose(rect1.Width, rect2.Width);
        } 

        /// <summary> 
        /// 
        /// </summary>
        /// <param name="val"></param> 
        /// <returns></returns>
        public static bool IsBetweenZeroAndOne(double val)
        {
            return (GreaterThanOrClose(val, 0) && LessThanOrClose(val, 1)); 
        }

        /// <summary> 
        ///
        /// </summary> 
        /// <param name="val"></param>
        /// <returns></returns>
        public static int DoubleToInt(double val)
        { 
            return (0 < val) ? (int)(val + 0.5) : (int)(val - 0.5);
        } 


        /// <summary> 
        /// rectHasNaN - this returns true if this rect has X, Y , Height or Width as NaN.
        /// </summary>
        /// <param name='r'>The rectangle to test</param>
        /// <returns>returns whether the Rect has NaN</returns> 
        public static bool RectHasNaN(Rect r)
        { 
            if (    DoubleUtil.IsNaN(r.X) 
                 || DoubleUtil.IsNaN(r.Y)
                 || DoubleUtil.IsNaN(r.Height) 
                 || DoubleUtil.IsNaN(r.Width) )
            {
                return true;
            } 
            return false;
        } 


#if !PBTCOMPILER 

        [StructLayout(LayoutKind.Explicit)]
        private struct NanUnion
        { 
            [FieldOffset(0)] internal double DoubleValue;
            [FieldOffset(0)] internal UInt64 UintValue; 
        } 

        // The standard CLR double.IsNaN() function is approximately 100 times slower than our own wrapper, 
        // so please make sure to use DoubleUtil.IsNaN() in performance sensitive code.
        // PS item that tracks the CLR improvement is DevDiv Schedule : 26916.
        // IEEE 754 : If the argument is any value in the range 0x7ff0000000000001L through 0x7fffffffffffffffL
        // or in the range 0xfff0000000000001L through 0xffffffffffffffffL, the result will be NaN. 
        public static bool IsNaN(double value)
        { 
            NanUnion t = new NanUnion(); 
            t.DoubleValue = value;

            UInt64 exp = t.UintValue & 0xfff0000000000000;
            UInt64 man = t.UintValue & 0x000fffffffffffff;

            return (exp == 0x7ff0000000000000 || exp == 0xfff0000000000000) && (man != 0); 
        }
#endif 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

EDIT: 编辑:
As others pointed out: the tests in the question both do produce Equal. 正如其他人指出的那样:问题中的检验确实都产生了相等性。 The above discussion however still holds, just not for these specific tests. 然而,以上讨论仍然成立,只是不针对这些特定测试。

Your output is wrong. 您的输出错误。 in above mention query float and double values are equal. 在上面提到的查询中,float和double值相等。 when you run this above program it will print two times "Equals". 当您运行上述程序时,它将打印两次“等于”。

You should again check your program output. 您应该再次检查程序输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM