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