Live data from Hacker News

C++ float-to-int conversion can be undefined behavior

kttnr.net

61–70 of 70 posts

Re: C++ float-to-int conversion can be undefined behavior

#61
post #56

Earlier quoted context omitted.

If the C++ standard imposes no requirements on such a program, then that means that the program is not C++ . It's quite reasonable to describe such a program as an "incorrect [C++] program."

This is a semantic quagmire, and the threads on what undefined behaviour is are interminable. But just note this time around that correctness is not the same as conformity.

Semantics matter to compiler vendors though, which is why C++ 26 now introduced erroneous behaviour as an attempt to fix UB.

Re: C++ float-to-int conversion can be undefined behavior

#62
post #30
post #25

Sounds like the standard should say that it results in an implementation-defined value (or wording to that effect). Saying it's UB gives the compilers way too much leeway.

Its incredibly hard to get changes like this into the standard, because there's a core contingent of people who seem to feel that UB is part of C++'s identity, and then there's very vague hand waving about performance. There is luckily a pretty successful push in wg21 to start removing a lot of the more unnecessary UB, so hopefully this gets sent to the sausage factory as well

You're the one doing the hand waving here. There are absolutely cases where UB is important for the optimizer. Float to int overflow is not one of them.

Re: C++ float-to-int conversion can be undefined behavior

#63

Earlier quoted context omitted.

Nitpick: Rust doesn't panic in this situation, it saturates (i.e., returns the largest possible value for the given integer type). Among other reasons, because a lot of existing programs that triggered this UB happened to work in practice, and would have experienced the panicking behavior as a severe regression. This case also shows the limits of Rust's safety culture; they knew about the problem for a long time, and…

It's interesting to consider that the same question would've surely come up during C and C++ language development, but that the answer is informed by the impact on the ecosystem, which was dramatically different when C, C++, and Rust were all being developed.

I don't think it would "surely come up". The C++ community is very comfortable with "Don't do that" as the lesson even though it's not actionable.

Like I said, safety is cultural. You can invent this stuff, somebody did, but the way most people end up doing it isn't because they all spontaneously invented the same solution, it was absorbed from their culture. C++ culture says "Don't do that" all the time instinctively. An actual concrete objection to fixing it might be offered if you insist on one, but they start with "Don't do that".

Sorting is my go-to example. Rust's sorts are safe. If I sort "Alligator", "Baboon", "Cat", "Donkey" then no matter what my ordering rule was nothing crazy happens. If my rule was nonsense, like "Every item is before every other item" then Rust might panic, it is allowed to do that - but otherwise it just will give me back the same four items but who knows what order because my ordering rule is nonsense. That seems easy enough, right?

In C++ if my ordering rule does not meet the precise requirements of the C++ language then all bets are off, that's Undefined Behaviour. I might get back "Cat", "Cat", "Cat", "Cat" even though there was originally only a single cat, or it might scribble past the end of my list of animals, crash, or anything at all. And while it would be permissible for real C++ standard library implementations to do better, on the whole they don't. "Don't do that" is the answer if you ask why this defect is allowed.

Re: C++ float-to-int conversion can be undefined behavior

#64
post #30

Earlier quoted context omitted.

Its incredibly hard to get changes like this into the standard, because there's a core contingent of people who seem to feel that UB is part of C++'s identity, and then there's very vague hand waving about performance. There is luckily a pretty successful push in wg21 to start removing a lot of the more unnecessary UB, so hopefully this gets sent to the sausage factory as well

You're the one doing the hand waving here. There are absolutely cases where UB is important for the optimizer. Float to int overflow is not one of them.

I think you might be misreading GP? They're basically agreeing with GGP ("so hopefully this gets sent to the sausage factory as well"); they're just saying that the process of actually changing the standard to remove (this kind of) UB is/has been rather challenging.

Re: C++ float-to-int conversion can be undefined behavior

#65
post #56

Earlier quoted context omitted.

If the C++ standard imposes no requirements on such a program, then that means that the program is not C++ . It's quite reasonable to describe such a program as an "incorrect [C++] program."

This is a semantic quagmire, and the threads on what undefined behaviour is are interminable. But just note this time around that correctness is not the same as conformity.

What's the difference? There's no such thing as "incorrect C++, but still C++." A program is either correct/valid/conforming C++, or it's not. We can reasonably describe "not" as "incorrect," or "invalid," "nonconforming," or just "not C++."

Re: C++ float-to-int conversion can be undefined behavior

#66

Earlier quoted context omitted.

Nitpick: Rust doesn't panic in this situation, it saturates (i.e., returns the largest possible value for the given integer type). Among other reasons, because a lot of existing programs that triggered this UB happened to work in practice, and would have experienced the panicking behavior as a severe regression. This case also shows the limits of Rust's safety culture; they knew about the problem for a long time, and…

> Rust doesn't panic in this situation, it saturates Yes sorry, in my head I'm thinking about what I'd want here because I do not like any of Rust's 'as' casts and in fact the thing I'd want here (TryInto) just does not exist on purpose for this reason. I wonder if I've ever run into this, realised I can't write a TryInto and if so what did I end up doing - interesting.

It's actually quite straightforward to write a TryFrom impl that returns Err if the conversion fails (i.e., if the input floating-point value is infinite, NaN, or out of range of the target integer type). The reason this hasn't been done is, what if the input is within range but has a nonzero fractional part? Do you truncate or round (meaning the conversion can sometimes be lossy), or do you return Err unless the conversion can be done losslessly? It's not obvious which behavior is right, but they'd have to pick one.

Re: C++ float-to-int conversion can be undefined behavior

#67

Herb Sutter's comment on why it's ok is confusing to me: > Regarding the use of UB internally: It's okay and if anyone is worried about it the use of UB is benign on the platforms we target (e.g., they don't involve hitting any hardware trap representations for these types) Isn't the outcome of the UB (ie. whether it will "rm -rf /" or something else) dependent on both the target and the compiler? And the compiler (o…

At this point of time Herb Sutter was working for Microsoft. When he says "we" the compiler team is included.

What he means is that, it works for Microsoft as it is and zero fucks are given for other compilers and platforms.

Re: C++ float-to-int conversion can be undefined behavior

#68
post #53

Earlier quoted context omitted.

I am not claiming there is any special treatment at all. I think the situation is much simpler: They (Microsoft) test GSL with specific compiler versions to observe how their usage of the UB is treated, and if satisfactory, that compiler version is now "supported" in their eyes. They do not claim to "support" any other version because they have not tested them to know how the UB functions there.

What is the relationship between your claim, and the claim I replied to about GSL having special treatment? In other words, why did you reply to me with an interpretation about a post that claimed GSL is afforded special treatment by MSVC if your claim is that GSL does not get any special treatment from MSVC? Did you intend to reply to someone else?

I'm not sure exactly where the disagreement really is. Perhaps when OP said "ensure that the changes were reverted or fixed to support" you were thinking they meant MSVC reverting changes, while I was thinking of GSL doing it instead, in order to "support" specific compiler versions they have on hand at the time to test.

Either way I think we are on the same page in thinking that compilers don't know/care that GSL exists and aren't doing anything special for it, and that's good enough for me.

Re: C++ float-to-int conversion can be undefined behavior

#69

Earlier quoted context omitted.

> Rust doesn't panic in this situation, it saturates Yes sorry, in my head I'm thinking about what I'd want here because I do not like any of Rust's 'as' casts and in fact the thing I'd want here (TryInto) just does not exist on purpose for this reason. I wonder if I've ever run into this, realised I can't write a TryInto and if so what did I end up doing - interesting.

It's actually quite straightforward to write a TryFrom impl that returns Err if the conversion fails (i.e., if the input floating-point value is infinite, NaN, or out of range of the target integer type). The reason this hasn't been done is, what if the input is within range but has a nonzero fractional part? Do you truncate or round (meaning the conversion can sometimes be lossy), or do you return Err unless the con…

Sure. These decisions are tricky, I had this concern in `realistic` too.

My `Rational` type is the "big rationals" (the finite subset of rational numbers I can represent with your available RAM) and these are certainly able to precisely represent any 32-bit or 64-bit float which isn't NaN or an infinity. However, vice versa is not true of course. 0.1 is a very easy Rational, but of course binary floating point cannot represent this exactly.

In the end I punted, TryInto is implemented for f32 and f64 but the opposite is not provided at all.

Re: C++ float-to-int conversion can be undefined behavior

#70
post #60
post #44

Today people think that Java's main feature was OOP, but its main selling point was "no undefined behavior" (e.g. "int" means 32-bit signed integer with overflows, on any platform, no exceptions). Today it sounds normal, but back in the day that was what made Java popular.

As someone that jumped into Java already in 1996, even though it was still interpreted, JIT would only come into early 2000's, there was another big factor, the standard library. Contrary to what people think nowadays, trying to write portable C or C++ code in the 90's was still an adventure. C compilers were still getting C89 compliance, and POSIX wasn't as portable as folks think. C++ was even worse, C++ARM was the…

Yes, forgot about that.

Aren't C/C++ compilers also very diverse today as well? GCC vs CLang with its intermediate representation sound like different planets.

Post reply on HN