Live data from Hacker News

Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

1f6042.blogspot.com

51–60 of 152 posts

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#51
post #47
post #45

Earlier quoted context omitted.

It shouldn’t be scary. Any library that is sensitive to order of operations will hopefully have a big fat warning on it. And it can be compiled separately with fast-math disabled. I don’t know of any such libraries off the top of my head, and it’s quite rare to find situations that result in orders of magnitude more error, though I grant you it can happen, and it can be contrived pretty easily.

You can't fully disable fast-math per-library, moreover a library compiled with fast-math might also introduce inaccuracies in a seemingly unrelated library or application code in the same executable. The reason is that fast-math enables some dynamic initialization of the library that changes the floating point environment in some ways.

you're gonna hive to give us a concrete real world example to convince most of us...

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#52
post #48
post #46

Earlier quoted context omitted.

Another PSA is that dynamic libraries compiled with fast-math will also introduce inaccuracies in unrelated libraries in the same executable, as they introduce dynamic initialization that globally changes the floating point environment.

This would only affect code that uses the old-school x87 floating point instructions, though? The x87 FPU unit indeed has scary global state that can make your doubles behave like floats in secret and silence. I would think practically all modern FPU code on x86-64 would be using the SIMD registers which have explicit widths.

So it was a bit more pervasive than this, the issue was that flushing subnormals (values very close to 0) to 0 is a register that gets set, so if a library is built with the fastmath flags and it gets loaded, it sets the register, causing the whole process to flush it's subnormals. i.e https://github.com/llvm/llvm-project/issues/57589

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#53
post #23

Earlier quoted context omitted.

Ehh, not so much inaccurate, more of a "floating point numbers are tricky, let's act like they aren't". Compilers are pretty skittish about changing the order of floating point operations (for good reason) and ffast-math is the thing that lets them transform equations to try and generate faster code. IE, instead of doing "n / 10" doing "n * 0.1". The issue, of course, being that things like 0.1 can't be perfectly rep…

It isn't just that. -ffast-math also allows the compiler to ignore infinites. In fact for GCC with -ffast-math, isinf always returns false. Something similar happens for NaNs/isnan.

I lump this into "floating points are tricky". NaNs and inf are definitely legitimate floating point values. They are also things that a lot of applications will break on they ever encounter them.

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#54
Depending on the order of the arguments to min max you'll get an extra move instruction [1]:

std::min(max, std::max(min, v));

        maxsd   xmm0, xmm1
        minsd   xmm0, xmm2
std::min(std::max(v, min), max);

        maxsd   xmm1, xmm0
        minsd   xmm2, xmm1
        movapd  xmm0, xmm2
For min/max on x86 if any operand is NaN the instruction copies the second operand into the first. So the compiler can't reorder the second case to look like the first (to leave the result in xmm0 for the return value).

The reason for this NaN behavior is that minsd is implemented to look like `(a Possibly std::clamp has the comparisons ordered like the second case?

[1]: https://godbolt.org/z/coes8Gdhz

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#55

Earlier quoted context omitted.

Ehh, not so much inaccurate, more of a "floating point numbers are tricky, let's act like they aren't". Compilers are pretty skittish about changing the order of floating point operations (for good reason) and ffast-math is the thing that lets them transform equations to try and generate faster code. IE, instead of doing "n / 10" doing "n * 0.1". The issue, of course, being that things like 0.1 can't be perfectly rep…

I've never understood why generating exceptions is preferable to just using higher precision.

On a GPU, higher precision can cost between 2 and 64 times more than single precision, with typical ratios for consumer cards being 16 or 32. Even on the CPU, fp64 workloads tend to run at half the speed on real data due to the extra bandwidth needed for higher precision.

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#56

Earlier quoted context omitted.

Try switching to -Ofast it produces different ASM

-Ofast is one of those dangerous flags that you should probably be careful with. It is “contagious” and it can mess up code elsewhere in the program, because it changes processor flags. I would try a more specific flag like -ffinite-math-only.

finite-math-only is a footgun as well as it allows the compiler assume that NaNs do not exist. Which means all `isnan()` calls are just reduced to `false` so it’s difficult to program defensively. And if a NaN in fact occurs it’s naturally a one-way ticket to UB land.

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#57
post #37
post #11

Earlier quoted context omitted.

You (celegans25) probably know this but here is a PSA that -ffast-math is really -finaccurate-math. The knowledgeable developer will know when to use it (almost never) while the naive user will have bugs.

Why do you say almost never? Don’t let the name scare you; all floating point math is inaccurate. Fast math is only slightly less accurate, I think typically it’s a 1 or maybe 2 LSB difference. At least in CUDA it is, and I think many (most?) people & situations can tolerate 22 bits of mantissa compared to 23, and many (most?) people/situations aren’t paying attention to inf/nan/exception issues at all. I deal with a…

> Fast math is only slightly less accurate

'slightly'? Last I checked, -Ofast completely breaks std::isnan and std::isinf--they always return false.

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#58
post #31

Earlier quoted context omitted.

I've never understood why generating exceptions is preferable to just using higher precision.

Higher precision isn’t always available. IEEE 754 is an unusually well-thought-through standard (thanks to some smart people with a lot of painful experience) and is pretty good at justifying its decisions, some of which are surprising (far from obvious) to anyone not steeped in it.

The main problem with floats in general is they are designed primarily for scientific computing.

We are fortunately starting to see newer (well, not that new now) CPU instructions like FMA that make more accurate decimal representations not take such huge performance hits.

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#59
post #47
post #45

Earlier quoted context omitted.

It shouldn’t be scary. Any library that is sensitive to order of operations will hopefully have a big fat warning on it. And it can be compiled separately with fast-math disabled. I don’t know of any such libraries off the top of my head, and it’s quite rare to find situations that result in orders of magnitude more error, though I grant you it can happen, and it can be contrived pretty easily.

You can't fully disable fast-math per-library, moreover a library compiled with fast-math might also introduce inaccuracies in a seemingly unrelated library or application code in the same executable. The reason is that fast-math enables some dynamic initialization of the library that changes the floating point environment in some ways.

> You can’t fully disable fast-math per library

Can you elaborate? What fast-math can sneak into a library that disabled fast-math at compile time?

> fast-math enables some dynamic initialization of the library that changes the floating point environment in some ways.

I wasn’t aware of this, I would love to see some documentation discussing exactly what happens, can you send a link?

Re: Std: Clamp generates less efficient assembly than std:min(max,std:max(min,v))

#60
post #45
post #43

Earlier quoted context omitted.

The scary thing IMO is: your code might be fine with unsafe math optimisations, but maybe you're using a library which is written to do operations in a certain order to minimise numerical error, and unsafe math operations changes the code which are mathematically equivalent but which results in many orders of magnitude more numerical error. It's probably fine most of the time, but it's kinda scary.

It shouldn’t be scary. Any library that is sensitive to order of operations will hopefully have a big fat warning on it. And it can be compiled separately with fast-math disabled. I don’t know of any such libraries off the top of my head, and it’s quite rare to find situations that result in orders of magnitude more error, though I grant you it can happen, and it can be contrived pretty easily.

I don't typically thoroughly read through the documentation for all the dependencies which my dependencies are using.

But you're correct that it's probably usually fine in practice.

Post reply on HN