From the manual:
An implementation should always use the maximum precision available to evaluate floating pointer values at compile time;
So if I store a float as float32, I see loss of precision. But if I type-convert to float32 and compare, I see none.
let x: float64 = 47.11 assert x == 47.11 # passes let y: float32 = 47.11'f32 assert y == 47.11 # fails, since the down-converted y becomes 47.11000061035156 assert y == 47.11'f32 # also fails! but why? assert y == float32(47.11) # same questionI guess the conversion from the default f64 down to f32 does not actually occur unless absolutely necessary. I can understand this beahavior, but since cfloat is 32-bit, it causes problems with c2nim.
As a rule you should never do equality test with floats (64bits or otherwise).
Instead, do something like this:
abs(f0 - f1) < 1E-7
<insert search engine here> is your friend
There are a plenty of articles written on floating point comparison.
Again, I disagree that this is an issue of "floating point comparison", and I am quite knowledgeable in this domain. You are entitled to your opinion as I am to mine.
Here is an example of something that you cannot do (afaict) in Nim:
Thanks for writing an answer that does not suggest an epsilon. This blog post I wrote some time ago has more examples of behaviors that may be surprising. http://blog.frama-c.com/index.php?post/2011/11/08/Floating-point-quiz – Pascal Cuoq
This is a real problem -- not terrible, but surprising and worth knowing. Type-conversion from float64 to float32 is not actually altering the floating-point representation. ==(float32, float32) is misleading. I do not suggest any correction, but I am recording this for posterity.
I would agree that this is not quite as expected. In the generated C code, the 47.11'f32 literal becomes 4.7109999999999999e+01, i.e., it has higher precision than y. One might think that an explicit conversion should help, but I think it is optimised away. If you need a work-around, wrapping the conversion in a function does work:
proc forceF32[T](x: T): float32 = x.float32 let y: float32 = 47.11'f32 # the 'f32 actually doesn't matter assert forceF32(47.11'f32) == y # ok assert float32(47.11'f32) == y # fails
This is just a bug and should be reported
let y: float32 = 47.11'f32 assert y == 47.11'f32 # <---- this really should be true.EDIT: I reported the bug here: https://github.com/nim-lang/Nim/issues/5821
To sum up the problem. The literal 47.11'f32 is translated into a double literal in C when translating to C. Therefore the comparison y == 47.11'f32 has a literal of type double (float64) on the right side in the generated C code. The C compiler then adds an implicit conversion from float to double on the left side and the comparison takes place in double (float64) not float (float32).