Re: How to overload == for System.Double

Marc Brooks <[email protected]> Thu, 1 Feb 2007 16:12:50 -0600
Newsgroups gmane.comp.windows.devel.dotnet.cx
Message-ID <[email protected]>
> Is it possible?

No.  Operators are specially recognized, and changing the behavior
would be wrond anyway.  Use this:

        public static partial class Utilities
        {
                /// <summary>
                /// Allows reinterpretation conversion doubles to/from longs AND
floats to/from ints to allow direct
                /// manipulation of the bit patterns.  Similar to
BitConverter.DoubleToInt64 and
                /// BitConverter.Int64ToDouble, but also works for floats/ints. Uses
a clever trick of explicit
                /// struct layout to insure that the same memory is used for all
values suggested by Jeroen Frijters
                /// see http://groups.yahoo.com/group/win_tech_off_topic/message/31670
                /// </summary>
                [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
                private struct BitReinterpreter
                {
                        public static int Convert(float f)
                        {
                                BitReinterpreter br = new BitReinterpreter(f);
                                return br.i;
                        }

                        public static float Convert(int i)
                        {
                                BitReinterpreter br = new BitReinterpreter(i);
                                return br.f;
                        }

                        public static long Convert(double d)
                        {
                                BitReinterpreter br = new BitReinterpreter(d);
                                return br.l;
                        }

                        public static double Convert(long l)
                        {
                                BitReinterpreter br = new BitReinterpreter(l);
                                return br.d;
                        }

                        [System.Runtime.InteropServices.FieldOffset(0)]
                        float f;
                        [System.Runtime.InteropServices.FieldOffset(0)]
                        int i;
                        [System.Runtime.InteropServices.FieldOffset(0)]
                        double d;
                        [System.Runtime.InteropServices.FieldOffset(0)]
                        long l;

                        private BitReinterpreter(float f)
                        {
                                this.l = 0;
                                this.d = 0;
                                this.i = 0;
                                this.f = f;
                        }

                        private BitReinterpreter(int i)
                        {
                                this.d = 0;
                                this.l = 0;
                                this.f = 0;
                                this.i = i;
                        }

                        private BitReinterpreter(double d)
                        {
                                this.i = 0;
                                this.f = 0;
                                this.l = 0;
                                this.d = d;
                        }

                        private BitReinterpreter(long l)
                        {
                                this.f = 0;
                                this.i = 0;
                                this.d = 0;
                                this.l = l;
                        }
                }

                /// <summary>
                /// Compared two single precision floating-point values to see if
they are equal within a
                /// designated precision specified as the number of digits in the
last significant place
                /// </summary>
                /// <param name="left">The first value</param>
                /// <param name="right">The second value</param>
                /// <param name="maxUnitsInLastPlace">The maximum error in terms of
Units in the Last Place.
                /// This specifies how big an error we are willing to accept in
terms of the value of the
                /// least significant digit of the floating point number's representation.
                /// It can also be interpreted in terms of how many representable
doubles we are willing
                /// to accept between left and right. This function will allow
maxUnitsInLastPlace - 1 floats
                /// between left and right.</param>
                /// <returns>True if left and right are equal or nearly equal. False
if not nearly equal OR if
                /// either value is a NaN.</returns>
                public static bool AlmostEqual(float left, float right, int
maxUnitsInLastPlace)
                {
                        // If left or right 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 (float.IsInfinity(left) || float.IsInfinity(right))
                                return left == right;

                        // If left or right are a NAN, return false. NANs are equal to nothing,
                        // not even themselves.
                        if (float.IsNaN(left) || float.IsNaN(right))
                                return false;

                        // The check for left == right is because zero and negative zero
have different
                        // signs but are equal to each other.
                        if (Math.Sign(left) != Math.Sign(right))
                                return left == right;

                        int aInt = BitReinterpreter.Convert(left);

                        // Make aInt lexicographically ordered as a twos-complement int
                        if (aInt < 0)
                                aInt = (int)(0x80000000 - (uint)aInt);

                        int bInt = BitReinterpreter.Convert(right);

                        // Make bInt lexicographically ordered as a twos-complement int
                        if (bInt < 0)
                                bInt = (int)(0x80000000 - (uint)bInt);

                        // Now we can compare aInt and bInt to find out how far apart left and right
                        // are.
                        int intDiff = Math.Abs(aInt - bInt);

                        if (intDiff <= maxUnitsInLastPlace)
                                return true;

                        return false;
                }

                /// <summary>
                /// Compared two double precision floating-point values to see if
they are equal within a
                /// designated precision specified as the number of digits in the
last significant place
                /// </summary>
                /// <param name="left">The first value</param>
                /// <param name="right">The second value</param>
                /// <param name="maxUnitsInLastPlace">The maximum error in terms of
Units in the Last Place.
                /// This specifies how big an error we are willing to accept in
terms of the value of the
                /// least significant digit of the floating point number's representation.
                /// It can also be interpreted in terms of how many representable
doubles we are willing
                /// to accept between left and right. This function will allow
maxUnitsInLastPlace - 1 floats
                /// between left and right.</param>
                /// <returns>True if left and right are equal or nearly equal. False
if not nearly equal OR if
                /// either value is a NaN.</returns>
                public static bool AlmostEqual(double left, double right, long
maxUnitsInLastPlace)
                {
                        // If left or right 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 (double.IsInfinity(left) || double.IsInfinity(right))
                                return left == right;

                        // If left or right are a NAN, return false. NANs are equal to nothing,
                        // not even themselves.
                        if (double.IsNaN(left) || double.IsNaN(right))
                                return false;

                        // The check for left == right is because zero and negative zero
have different
                        // signs but are equal to each other.
                        if (Math.Sign(left) != Math.Sign(right))
                                return left == right;

                        long aInt = BitReinterpreter.Convert(left);

                        // Make aInt lexicographically ordered as a twos-complement int
                        if (aInt < 0)
                                aInt = (long)(0x8000000000000000 - (ulong)aInt);

                        long bInt = BitReinterpreter.Convert(right);

                        // Make bInt lexicographically ordered as a twos-complement int
                        if (bInt < 0)
                                bInt = (long)(0x8000000000000000 - (ulong)bInt);

                        // Now we can compare aInt and bInt to find out how far apart A and B
                        // are.
                        long intDiff = Math.Abs(aInt - bInt);

                        if (intDiff <= maxUnitsInLastPlace)
                                return true;

                        return false;
                }
        }

--
"I am Dyslexic of Borg. Resistors are fertile. Prepare to have your
ass laminated." -- Dan Nitschke

Marc C. Brooks
http://musingmarc.blogspot.com

===================================
This list is hosted by DevelopMentor®  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com