简体   繁体   中英

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?


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. In my case, d is the result of a conversion that occurs in code generated by light weight code generation. 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 . 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:

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.

It really depends on what you'll be using d for. 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 .

To compare two float point values ibm sugests to test 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.

so actually you should check

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

(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. 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.

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. 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. Then (float) d == f evaluates to (float) 0 == 0x1p-1000 , then to 0 == 0x1p-1000 , then to 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 .

Other than that, what errors would you be trying to detect with an assertion here?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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