在C#中复制后是否可以保证double / float相等?

时间:2018-10-23 16:14:44

标签: c# floating-point equality

对于一个非常简单的问题,我找不到清晰,简单的答案!我将问题分为两个版本。

在C#中,假设我运行以下命令:

double x = 76239.78362194721;
double y = -3;
y = x;  // copied by value, as doubles are literals
//y = y + 1.4;  // Version 1 of my question has these commented-out
//x = x + 1.4;  // Version 2 of my question has these not commented-out
bool b = (x == y);

布尔值b 总是是真的吗?也就是说,尽管双精度之间的相等性度量不准确,但是计算机永远不会故意添加噪音吗?

b能否取决于我要问的是版本1还是版本2? (我们可以假设xy 不是接近double的最大值或最小值,也不接近ε的正负值。

谢谢! 〜格雷格

1 个答案:

答案 0 :(得分:-1)

使用y = x;复制不会造成任何精度损失。

分配后,x == y为真。

由于xy相等,因此

y = y + 1.4;
x = x + 1.4;

x == y很可能是正确的;但是,正如埃里克·利珀特(Eric Lippert)指出的那样(请参见下面的评论),这不能保证。

始终将双精度与所需精度进行比较:

const double Eps = 1e-10;
if (Math.Abs(x - y) < Eps) {
    // x and y are equal enough
} else {
    // x and y are not equal
}

当然,如果您仅注释掉其中之一,则xy将相差约1.4。它们可能相差1.3999999999999991.400000000000001左右。如果两者都很大(例如1.0e25),则加法将无效,因为它将影响被截断的小数。 double的精度为15到16位数字。如果两者都很小(例如1.0e-25),也是如此,因为这样它们的原始值将丢失,结果将是1.4

在“ C#交互式”窗口中,您可以进行测试

> 1e+25 + 1.4 == 1e+25
true

> 1e-25 + 1.4 == 1.4
true

  

...按值复制,因为双精度为文字

嗯,不完全是。 System.Double(C#别名double)是值类型3.141592654double文字。在double x;中,标识符x是一个double变量(如果在类型级别声明,则为字段)。

但是即使您复制...

var p1 = new Person { Name = "John" }; // Where Person is a class.
var p2 = p1;
// Now, p1 and p2 reference the same object. I.e. they have the same value.

...变量的值按值复制。区别在于此值是参考。该值不是人员对象,而是对其的引用。

p2.Name = "Mark";

现在p1.Name == "Mark"是正确的,但是p1的值没有改变。它仍然是相同的参考。引用的对象确实发生了变化。


double d1 = 5;
double d2 = d1;
d2 = 77;

d1仍为5。由于double是值类型,因此变量直接包含数字。不涉及任何参考。


在另一个示例中,引用是通过引用传递的

var p1 = new Person{ Name = "John" };
AssignAnotherPerson(ref p1);

void AssignAnotherPerson(ref Person p)
{
    p = new Person{ Name = "Sue" }; // Here p is an alias for p1.
}

调用此方法后,p1将包含个人Sue。

您可以有四种情况:(1)通过值传递的值类型。 (2)通过引用传递的值类型。 (3)按值传递的引用类型。 (4)通过引用传递的引用类型。