assert(x == 7); // fine
assert(y == NaN); // never true
assert(y != y); // this is what you meant
so this equiv() helper fixes that, assert(equiv(x, 7)); // fine
assert(equiv(y, NaN)); // also fine
now, as far as treating NaNs equivalently, the IEEE 754 float format has a huge number of possible representations of NaN, and if you did something like a bitwise comparison, you might think that 0x7fc00000, 0x7f800001, 0xffc00000, 0x7fc0f00d were all different and not equivalent, but they're all NaNs, and I find that when I'm looking for a NaN, I very rarely care about exactly which one I'm looking at. So checking (x!=x && y!=y) admits any two NaNs as equivalent. _Bool equiv(float x, float y) {
return (x <= y && y <= x)
|| (x != x && y != y);
}
which both handles NaNs sensibly (all NaNs are equivalent) and won't warn about using == on floats. I find it also easy to remember how to write when starting a new project. struct foo {
_Alignas(64) float x,y;
_Alignas(64) int z;
};
_Static_assert(sizeof(struct foo) == 192, "");
I see it as something like a personal gradient descent. You're working on a problem, there are solutions down there somewhere, and you can kind of feel the gradient of the tools-and-techniques ground around you. Any way you walk means you're investing time improving some skill or another. So you should go the way that personally feels to you will best get you moving in the direction that you want to go.
For some people it's obvious LLMs are competent coders, getting better, sticking around... and those people should lean into that gradient. For some people what's obvious is nearly the exact opposites of all that, and I'd encourage those people to also follow their gradient/heart/nose down the path of sharpening their personal traditional coding skills. Some people are in a relatively flat area where nothing is obvious, and need to explore and maybe just keep doing their best to hedge with a bit of both.