GCC really does suck at math.
While porting my game to 64-bit Linux, I encountered some strange behavior under certain circumstances in which the game didn't seem to know what the fuck it was doing, and would eventually lock up.
After spending six hours tracking down the bug, I find it's this:fesetround(FE_DOWNWARD) causes cos() to return values outside the range of -1 to +1
Note that the bug referenced in the comments isn't on the same bug tracker. I managed to track it down once, but have since been unable to discover where the glibc bug tracker is. It's very well hidden, wherever it is.
In that bug report, someone states (five years ago) that they found similar incorrect results with functions like exp() and cosh(). Five years later, someone posts that they've fixed the problem in exp(), cosh() and sinh(), and that if any other functions have similar issues, someone should report them in seperate bugs.
In other words, a really stupid bug exists in some math functions and they don't care to take the time to see if similar stupidity exists in other similar functions, like sin() and cos(). Indeed, they didn't seem to want to take the time to fix even exp(), cosh() and sinh(), given that they took five years to simply wrap the functions in calls to fesetround() to set the rounding mode they expect.
...and, again, none of this would have happened if they were simply using the FPU rather than glibc.
I looked at the 64-bit cos() function. ...or tried to, but couldn't find it. However, I did find the sin() function. It's 5,000 instructions long, and computes the value using addition, multiplication, and conditional jumps. Somehow it only takes 20% longer than the FCOS instruction.
Why do they calculate the value manually, with great (and realized) potential for error, rather than simply using the FPU instruction to calculate the value faster? Who the fuck knows. They even calculate the value using 64-bit floats, whereas the FPU would calculate it using 80-bit floats and only round the result to 64-bit floats.
So I did some tests. Compiling for 32-bit on a 64-bit system, and using --fast-math, fesetround(), and nearbyint(), creates math that runs twice as fast
as 64-bit math with default settings. ...and using --fast-math on 64-bit? That only puts a dent in the time it takes. For the most part, even with --fast-math, GCC still calls glibc to do math.
Seems the best we can do now is this:#define round(x) rint(x)
Anyway, I've switched to FreeBSD. (not that it's terribly relevant to this discussion)
FreeBSD has its own C library. It's snprintf() always puts a null character at the end of the string. ...and they use OSS instead of some garbage like ALSA, and up to 16 applications can open the device at once, unlike Linux's OSS implementation (which is disabled by default) which only allows one process to open the device at a time. ...and the audio mixing is done in the kernel, vs. Linux where they've decided to adopt the microkernel approach on just this one issue, declaring that anything that doesn't have to be done in the kernel shouldn't be done in the kernel. Thus you can't use sound in Linux without using ALSAlib as there is no ABI because you can't mix audio in user space without all of the processes using the same library in order to cooperatively share the audio device. Didn't we learn back in the 90's that cooperative multitasking is a bad idea? ...and like most libraries, ALSAlib is far more difficult than it should be.
I love FreeBSD. Sure, it sucks to have to learn something new, and the lack of Flash and Java is kind of annoying, but the lack of freetard design is awesome! The "ports" system is just like how Gentoo would work if Gentoo weren't freetarded. Compile from source if you want to, or install a binary package if you don't want to wait all day, and there's no infinite number of USE flags to examine and decide whether or not you need.
Those USE flags in Gentoo are a pain in the ass. Forget one and suddenly you need to recompile your whole system (another two days wasted) because you accidentally built it without jpeg support. Why the hell is that even possible? It's the freetard way, that's why. You compile from source because you demand that source be available because you're such a hacker! ...and by "hacker" I don't mean you're a criminal, I mean it the way that the freetards redefined the word. It now means "really good programmer." ...and not just now, but in the past as well, because they redefined it at the point of its introduction into the English langauge. They can do that you know. All they have to do is make up some story that "it always meant that but then the media used it to refer to criminals" and mindlessly repeat it simply because they like that version of reality better. So, anyway, you don't need binary packages because you examine the source of everything for security vulnerabilities before you compile it! ...and as long as you're doing that, you might as well strip out that jpeg support you don't need! I mean, you have no plans of opening a jpeg today, and you can always recompile if you change your mind! (I've decided the exclamation point, when used for sentences rather than exclamations, makes a good <sarcasm> tag.)
The FreeBSD people aren't even trying to make an open-source version of the NVIDIA driver. I love these people. They waste less time rewriting drivers for things with no documentation so they can spend more time making improvements where they'll actually make a difference.