I mean "surprising inequality", but I'm not talking about < or >. Here are the wrappers:

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 question
I 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.

2017-05-14 18:07:33

As a rule you should never do equality test with floats (64bits or otherwise).

Instead, do something like this:

abs(f0 - f1) < 1E-7

2017-05-14 18:10:29
That's slow, and not really the point. The equality comparison is used in regression-testing, where we want to set a value and then ensure that the value was actually set. 2017-05-14 18:27:11

<insert search engine here> is your friend

There are a plenty of articles written on floating point comparison.

2017-05-14 20:16:59

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.

2017-05-14 20:34:55

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

2017-05-14 21:52:10

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

2017-05-15 14:10:39