简体   繁体   English

浮动到双重转换 - 单元测试中的最佳断言?

[英]Float to Double conversion - Best assertion in a unit test?

Given the statements 鉴于这些陈述

float f = 7.1f;
double d = f;

What can we assert in a unit test about d? 我们可以在单元测试中断言d?


For example this does not work: 例如,这不起作用:

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)

The best way I found so far is to convert the value back: 我到目前为止找到的最好的方法是将值转换回来:

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

Which would be the same as the brute way to say 这与粗野的说法相同

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

This question is NOT about double and float precision in general but really JUST about the pragmatic question how a unit test can best describe the confines of d. 这个问题一般不是关于double和float精度的,而是关于单元测试如何最好地描述d的限制的实用问题。 In my case, d is the result of a conversion that occurs in code generated by light weight code generation. 在我的例子中,d是由轻量代码生成生成的代码中发生的转换的结果。 While testing this code generation, I have to make assertions about the outcome of this function and this finally boils down to the simple question above. 在测试这个代码生成时,我必须对这个函数的结果做出断言,这最终归结为上面的简单问题。

Your "best way" is asserting that your generated code returns something that is, within float 's margin of error, 7.1 . 你的“最佳方式”是断言你生成的代码返回的内容是float的误差范围7.1 This may be what you want to check, in which case, carry on. 这可能是你要检查的,在这种情况下,继续。

On the other hand, you might want to assert that your generated code returns specifically the result of casting 7.1f to a double , in which case you could do: 另一方面,您可能希望声明生成的代码特别返回将7.1f转换为double的结果,在这种情况下,您可以执行以下操作:

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

This is more stringent - your test asserts that d is within a small range, while the above test asserts that d is a specific value. 这是更严格的 - 您的测试断言d在一个小范围内,而上述测试断言d是一个特定值。

It really depends on what you'll be using d for. 这真的取决于你将使用什么d If it's a case where things will go wrong if it's not the exact value, test the exact value, but if it's OK to be within a float of the value, check against the float . 如果事情出现问题,如果它不是确切的值,请测试确切的值,但如果可以在值的float范围内,请检查float

To compare two float point values ibm sugests to test abs(a/b - 1) < epsilon 为了比较两个浮点值ibm sugest来测试abs(a/b - 1) < epsilon

an msnd states that Epsilon property reflects the smallest positive value that is significant in numeric operations or comparisons when the value of the instance is zero. msnd指出,当实例的值为零时, Epsilon属性反映了数值运算或比较中最重要的最小正值。

so actually you should check 实际上你应该检查一下

Math.Abs(d/(double)f) - 1) < float.Epsilon)

(float) d == f . (float) d == f

Another answer suggested d == (double) f , but this is a useless test because (double) f performs the same conversion that d = f implicitly performs. 另一个答案建议d == (double) f ,但这是无用的测试,因为(double) f执行与d = f隐式执行的相同转换。 So the only thing this assertion could be testing is whether some aspect of the implementation is broken (eg, the compiler implemented one of the conversions incorrectly and in a way different from the other), some external mechanism altered d or f between the assignment and the assertion, or the source code were broken so that d was neither double nor float nor any type that can hold the value of f exactly or the assignment d = f was not performed. 所以这个断言唯一可以测试的是实现的某些方面是否被破坏(例如,编译器错误地以不同的方式实现了其中一个转换),一些外部机制在赋值和之间改变了df 。断言或源代码被破坏,因此d既不是double也不是float也不是任何能够精确保存f值或者没有执行赋值d = f

Generally, we expect no floating-point error, because, in every normal implementation of floating-point, converting from a narrower precision to a wider precision of the same radix has no error, since the wider precision can represent every value the narrower precision can. 通常,我们期望没有浮点误差,因为在浮点的每个正常实现中,从较窄的精度到相同基数的更宽精度的转换没有错误,因为更宽的精度可以表示每个值,更窄的精度可以。 In uncommon situations, a wider floating-point format might have a smaller exponent range. 在不常见的情况下,较宽的浮点格式可能具有较小的指数范围。 Only in this case, or in perversely defined floating-point formats, could converting to a wider format cause a change in value. 只有在这种情况下,或者在反常定义的浮点格式中,转换为更宽的格式才会导致值的变化。 In these cases, performing the same conversion would not detect the change. 在这些情况下,执行相同的转换不会检测到更改。

Instead, we convert from the wider format back to the narrower format. 相反,我们从更宽的格式转换回更窄的格式。 If d differs from f , this conversion has a chance of detecting the error. 如果df不同,则此转换有可能检测到错误。 Eg, suppose f contained 0x1p-1000, but, for some reason, that is not representable in the format of d , so it was rounded to zero. 例如,假设f包含0x1p-1000,但由于某种原因,这在d的格式中是不可表示的,因此它被舍入为零。 Then (float) d == f evaluates to (float) 0 == 0x1p-1000 , then to 0 == 0x1p-1000 , then to false . 然后(float) d == f求值为(float) 0 == 0x1p-1000 ,然后为0 == 0x1p-1000 ,然后为false Additionally, this test may detect the same errors as the other suggestion: a broken implementation, alteration of d or f , an incorrect type of d , and a missing assignment of d = f . 另外,这种测试可以检测相同的错误,其他建议:一个破碎实施方式中,变更df ,一个不正确的类型的d ,而且缺少分配d = f

Other than that, what errors would you be trying to detect with an assertion here? 除此之外,你会在这里用断言检测到什么错误?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM