.Net中关于相等的问题
作者:Sweet-Tang 发布时间:[ 2017/6/28 10:45:43 ] 推荐标签:测试开发技术 .NET
浮点数的准确性
在.Net框架中,您如果使用到浮点数,可以带来一些意想不到的问题,让我们来看一个例子:
1 float num1 = 2.000000f;
2 float num2 = 2.000001f;
3
4 Console.WriteLine(num1 == num2);
我们有两个几乎相等的浮点数,但是很明显,它们不一样,因为它们在末尾的数字是不同的,我们运行程序,控制台打印输出的结果是True。
从程序来角度来讲,它们是相等的,这与我们预期结果矛盾。不过您可能已经猜测到问题出在哪里了,数字类型存在一个精度问题,float类型不能存储足够的有效数来区分这两个特定的数字,并且它还存在其它运算的问题。看这个例子:
1 float num1 = 0.7f;
2 float num2 = 0.6f + 0.1f;
3
4 Console.WriteLine(num2);
5 Console.WriteLine(num1 == num2);
这是一个简单的计算,我们将0.6与0.1相加,非常明显,相加后的结果是0.7,但是我们运行程序,控制台打印输出的结果是False,注意结果是False,这说明计算结果不等于0.7。其原因是,浮点数在运算的过程中出现了舍入误差导致了存储一个非常接近的数字,虽然num2转换成String类型后,在控制台打印输出的结果是0.7,但是num2的值并不等于0.7。
舍入误差意味着判断相等通常会给您一个错误的结果,.Net框架没有提供解决方案。给您的建议是,不要尝试比较浮点数是否相等,因为可能不是预期结果。这个问题只会影响等于比较,通常不会影响小于和大于比较,在大多数情况下,比较一个浮点数是大于还是小于另一个浮点数不会出该问题。
在stackoverflow上提供这样一个解决办法,供大家参考:https://stackoverflow.com/questions/6598179/the-right-way-to-compare-a-system-double-to-0-a-number-int。
值相等与面向对象之间的矛盾
这个问题对经验丰富的开发人员来说可能会感到很诧异,实际上这是等于比较、类型安全和良好的面向对象实践之间的冲突。这三个问题如果没有处理好,将会带来其它的Bug。
现在我们来举这样一个例子,假设我们有基类Animal表示动物,派生类Dog来表示狗。
1 public class Animal
2 {
3
4 }
5
6 public class Dog : Animal
7 {
8
9 }
如果我们希望在Animal类实现当前实例是否等于其它Animal实例,则可能需要实现接口IEquatable<Animal>。这要求它定义一个Equals()方法并以Animal类型的实例作为参数。
1 public class Animal : IEquatable<animal>
2 {
3 public virtual bool Equals(Animal other)
4 {
5 throw new NotImplementedException();
6 }
7 }
如果我们希望Dog类也实现当前实例是否等于其它Dog实例,那么可能需要实现接口IEquatable<Dog>,这意味着它也定义一个Equals()方法并以Dog类型的实例作为参数。
1 public class Dog : Animal, IEquatable<Dog>
2 {
3 public virtual bool Equals(Dog other)
4 {
5 throw new NotImplementedException();
6 }
7 }
现在问题出现了,在这个一个精心设计的OOP代码中,您可能会认为Dog类会覆盖Animal类的Equals()方法,但是麻烦的是Dog的Equals()方法与Animal类的Equals()方法使用的是不同的参数类型,实际是重写不了Animal类的Equals()方法。如果您不够仔细,可能会调用错误的Equals方法,终返回错误的结果。
通常的解决办法是重写Object类型Equals方法;该方法采用一个Object类型为参数类型,这意味着它不是类型安全的,但它能够正常重写基类的方法,并且这也是简单的解决办法。
总结
C#在语法上不区分值相等和引用相等,这意味着有时候很难预测在特定情况下"=="运算符是如何执行;
存在多种方式实现值相等判断,.Net框架允许类型定义默认的值比较方式,同时提供自己编写比较器的机制来实现每种类型的值比较;
不建议使用浮点数进行值相等比较,因为舍入误差可能导致结果超出预期;
值相等、类型安全和良好的面向对象之间存在冲突。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11