C#的浮点比较函数有人可以在C#中指向(或显示)一些好的通用浮点比较函数来比较浮点值吗?我想实现的功能IsEqual,IsGreater一个IsLess。我也只关心双打不漂浮。
3 回答
白板的微信
TA贡献1883条经验 获得超3个赞
编写一个有用的通用浮点IsEqual
是非常非常困难的,如果不是完全不可能的话。您当前的代码将严重失败a==0
。该方法应该如何处理这种情况实际上是一个定义的问题,并且可以说代码最适合特定的域用例。
对于这种事情,你真的需要一个好的测试套件。这就是我为浮点指南做的,这就是我最终提出的(Java代码,应该很容易翻译):
public static boolean nearlyEqual(float a, float b, float epsilon) { final float absA = Math.abs(a); final float absB = Math.abs(b); final float diff = Math.abs(a - b); if (a == b) { // shortcut, handles infinities return true; } else if (a == 0 || b == 0 || absA + absB < Float.MIN_NORMAL) { // a or b is zero or both are extremely close to it // relative error is less meaningful here return diff < (epsilon * Float.MIN_NORMAL); } else { // use relative error return diff / (absA + absB) < epsilon; }}
附录: c#中的相同代码用于双打(在问题中提到)
public static bool NearlyEqual(double a, double b, double epsilon){ const double MinNormal = 2.2250738585072014E-308d; double absA = Math.Abs(a); double absB = Math.Abs(b); double diff = Math.Abs(a - b); if (a.Equals(b)) { // shortcut, handles infinities return true; } else if (a == 0 || b == 0 || absA + absB < MinNormal) { // a or b is zero or both are extremely close to it // relative error is less meaningful here return diff < (epsilon * MinNormal); } else { // use relative error return diff / (absA + absB) < epsilon; }}
largeQ
TA贡献2039条经验 获得超7个赞
从Bruce Dawson关于比较浮点数的论文中,您还可以将浮点数作为整数进行比较。接近度由最低有效位确定。
public static bool AlmostEqual2sComplement( float a, float b, int maxDeltaBits ) { int aInt = BitConverter.ToInt32( BitConverter.GetBytes( a ), 0 ); if ( aInt < 0 ) aInt = Int32.MinValue - aInt; // Int32.MinValue = 0x80000000 int bInt = BitConverter.ToInt32( BitConverter.GetBytes( b ), 0 ); if ( bInt < 0 ) bInt = Int32.MinValue - bInt; int intDiff = Math.Abs( aInt - bInt ); return intDiff <= ( 1 << maxDeltaBits );}
编辑:BitConverter相对较慢。如果您愿意使用不安全的代码,那么这是一个非常快的版本:
public static unsafe int FloatToInt32Bits( float f ) { return *( (int*)&f ); } public static bool AlmostEqual2sComplement( float a, float b, int maxDeltaBits ) { int aInt = FloatToInt32Bits( a ); if ( aInt < 0 ) aInt = Int32.MinValue - aInt; int bInt = FloatToInt32Bits( b ); if ( bInt < 0 ) bInt = Int32.MinValue - bInt; int intDiff = Math.Abs( aInt - bInt ); return intDiff <= ( 1 << maxDeltaBits ); }
幕布斯7119047
TA贡献1794条经验 获得超8个赞
继Andrew Wang的回答:如果BitConverter方法太慢但你不能在你的项目中使用不安全的代码,这个结构比BitConverter快6倍:
[StructLayout(LayoutKind.Explicit)]public struct FloatToIntSafeBitConverter{ public static int Convert(float value) { return new FloatToIntSafeBitConverter(value).IntValue; } public FloatToIntSafeBitConverter(float floatValue): this() { FloatValue = floatValue; } [FieldOffset(0)] public readonly int IntValue; [FieldOffset(0)] public readonly float FloatValue;}
(顺便说一句,我尝试使用已接受的解决方案,但它(至少我的转换)失败了一些在答案中也提到的单元测试。例如assertTrue(nearlyEqual(Float.MIN_VALUE, -Float.MIN_VALUE));
)
- 3 回答
- 0 关注
- 1144 浏览
添加回答
举报
0/150
提交
取消