17

鉴于陈述

float f = 7.1f;
double d = f;

我们可以在单元测试中断言什么关于 d?


例如,这不起作用:

Console.WriteLine(d == 7.1d); // false
Console.WriteLine(d < 7.1d + float.Epsilon); // true by luck
Console.WriteLine(d > 7.1d - float.Epsilon); // false (less luck)

到目前为止,我发现的最好方法是将值转换回:

float f2 = (float)d;
Console.WriteLine(f2 == f); // true

这与粗鲁的说法相同

Console.WriteLine(d == 7.1f); // 7.1f implicitly converted to double as above

这个问题一般不是关于双精度和浮点精度,而只是关于单元测试如何最好地描述 d 范围的实用问题。在我的例子中,d 是由轻量级代码生成生成的代码中发生的转换的结果。在测试这个代码生成时,我必须对这个函数的结果做出断言,这最终归结为上面的简单问题。

4

3 回答 3

4

您的“最佳方法”是断言您生成的代码返回的内容在float' 的误差范围内,7.1. 这可能是您要检查的内容,在这种情况下,请继续。

另一方面,您可能想要断言生成的代码专门返回转换7.1f为 a的结果double,在这种情况下,您可以这样做:

Console.WriteLine(d == (double)f);

这是更严格的 - 您的测试断言d在一个小范围内,而上述测试断言这d是一个特定的值。

这真的取决于你将使用什么d。如果不是精确值会出错,请测试精确值,但如果可以在float值的 a 范围内,请检查float.

于 2012-12-19T13:02:23.220 回答
1

要比较两个浮点值, ibm 建议进行测试abs(a/b - 1) < epsilon

msnd 指出,Epsilon当实例的值为零时,该属性反映了在数值运算或比较中有意义的最小正值。

所以实际上你应该检查

Math.Abs(d/(double)f) - 1) < float.Epsilon)
于 2012-12-19T13:17:57.547 回答
1

(float) d == f.

建议的另一个答案d == (double) f,但这是一个无用的测试,因为执行隐式执行(double) f的相同转换。d = f所以这个断言唯一可以测试的是实现的某些方面是否被破坏(例如,编译器不正确地实现了其中一个转换并且以不同于另一个的方式),一些外部机制被改变df在赋值和断言之间, 或者源代码被破坏,因此d既不是double也不float是任何类型都可以准确地保存 的值,或者没有执行f赋值。d = f

通常,我们期望没有浮点错误,因为在浮点的每个正常实现中,从较窄的精度转换为相同基数的较宽的精度没有错误,因为较宽的精度可以表示每个值,较窄的精度可以. 在不常见的情况下,较宽的浮点格式可能具有较小的指数范围。只有在这种情况下,或者在错误定义的浮点格式中,转换为更广泛的格式才会导致值发生变化。在这些情况下,执行相同的转换不会检测到更改。

相反,我们从较宽的格式转换回较窄的格式。如果d与 不同f,则此转换有可能检测到错误。例如,假设f包含 0x1p-1000,但由于某种原因,它无法以 的格式表示d,因此将其四舍五入为零。然后(float) d == f评估为(float) 0 == 0x1p-1000,然后为0 == 0x1p-1000,然后为false。此外,此测试可能会检测到与其他建议相同的错误:实现损坏、更改dor f、不正确的类型d以及d = f.

除此之外,您会尝试通过此处的断言检测哪些错误?

于 2012-12-19T14:33:00.450 回答