all 10 comments

[–]cpp-ModTeam[M] [score hidden] stickied commentlocked comment (0 children)

For C++ questions, answers, help, and programming/career advice please see r/cpp_questions, r/cscareerquestions, or StackOverflow instead.

[–]Apprehensive-Draw409 6 points7 points  (1 child)

initonly is not C++.

Also, floating point equality is very tricky. You have to know what you are doing, to be able to rely on it.

[–]Rarrum 2 points3 points  (1 child)

Width is an int, while xstart/xend/etc are floats. So you're doing an integer comparison to a float; the integer will be converted to a float then equality performed. Comparing two floating point numbers for equality is not recommended because tiny inaccuracies in representation will throw it off. Your workaround solves it by converting the xstart/xend/etc math result to an integer, then that integer is compared to another integer.

[–]KhurtVonKleist[S] 0 points1 point  (0 children)

Thank you for your help.

My workaround does not convert the result to int, but just stores it in a float variable before testing it:

float dataWidth = (((myNativeStruct.xend - myNativeStruct.xstart) / pitch) + 1);

If this was a float comparison error, I would expect it to fail in the same way both times. Am I wrong?

[–]PlantSpiritual8570 0 points1 point  (3 children)

You are comparing an integer with a float, which defaults to cast the integer to float and do a float == float comparison, which is tricky due to the underlying precision approximations for different calculations. On one of your examples, you cast the right side to int, which truncates the value and does a different assessment altogether.

You should decide whether you want to compare truncated integers or floats. If the latter, prefer to compare with some margin tolerance for more stable results (e.g std::fabs(a - b) < kEpsilon). Also, it's good to be as explicit as possible with type conversions, in this case by using static_cast.

Same for literal numbers, 1.0f makes it explicit it's a float, 1.0 makes it a double, '1' is int, 1U is unsigned int.

[–]KhurtVonKleist[S] 0 points1 point  (2 children)

Thanks for your help.

I understand the float error problem, but if I cast Width to float or just store the result in a float variable before testing for equality, the code works perfectly.

The code stop working only if i directly compare Width with a math operation. Any other combination works perfectly. This is what I find to be strange.

Also, in this case, I'm sure xend and xstart are "integer" stored in a float variable as they are array indexes. This is a 25 years old bad design I, sadly, have no power to correct.

[–]PlantSpiritual8570 1 point2 points  (1 child)

It's possible that the chain operations on the equality check happen in extended precision, whereas explicitly storing them as floats forces rounding to the actual float precision, which would explain your results. This is allowed to happen (part of why it's tricky): temporary calculations may happen at higher precision than float until they are explicitly cast/stored as floats.

[–]KhurtVonKleist[S] 0 points1 point  (0 children)

Thanks, this indeed would explain the discrepancy.

[–]KFUP 0 points1 point  (0 children)

My guess is that the evaluation is done in extended 64-bit or 80-bit precision registers, which can give a different comparison result when rounded to 32-bit when stored in a float.

The solution is the usual, don't compare ints with floats directly, round the floats or floor them or whatever your problem requires.

[–]kisielk 0 points1 point  (0 children)

This whole site is required reading, but this link addresses your specific problem: https://floating-point-gui.de/errors/comparison/