0

I am working on float numbers as part of my project and I ran into this issue. I have two floats that are different. However, when I try to print them, it prints the same value. Can someone please help me understand what's happening? Is it related to the number of fractional digits that can be printed on the console?

Following is the MWE.

#include<stdint.h>
#include<iostream>

union FP32 {
    float f;
    uint32_t bits;
};

int main(void) {
    
    FP32 a, b;
    a.bits = 0x40800000;
    b.bits = 0x407FFFFF;
    std::cout << a.f << std::endl;
    std::cout << b.f << std::endl;
    return 1;
}   
RD1153
  • 115
  • 8
  • 1
    C++ doesn't allow you to use `union` like that. It is Undefined Behavior to read a member of a union that was not the most recently written to. `bits` is the most recently written to, you can't read `f`. The more portable way of doing this is to `memcpy` from a `uint32_t` to a `float` (provided you check that `sizeof(uint32_t) == sizeof(float)`. – François Andrieux Apr 29 '21 at 13:55
  • In that case, can you please tell me why the a.f is printing 4.0 which is expected value of the float? – RD1153 Apr 29 '21 at 13:59
  • Undefined Behavior doesn't mean that it will crash or give unexpected results. It means anything can happen. It can produce the expected result while you are observing it, but it the behavior can break at any time for any reason. Notable for `union` several compilers have non-standard extensions where they promise this works, but as far as the language is concerned it is not guaranteed to work. It can break if you change compiler, if you update your compiler or if you try it in a more complicated use case. – François Andrieux Apr 29 '21 at 14:04
  • See [here](https://en.cppreference.com/w/cpp/language/union#Explanation) and [Accessing inactive union member and undefined behavior?](https://stackoverflow.com/questions/11373203/accessing-inactive-union-member-and-undefined-behavior). – François Andrieux Apr 29 '21 at 14:05
  • @FrançoisAndrieux. Thanks for the explanation. In my case, my compiler seems to be okay using the union that way. I found that the reason for the rounding is because the cout precision is only 6 digits. I was able to fix it by cout.precision(20). Thanks anyway! – RD1153 Apr 29 '21 at 14:09
  • @RD1153 Print `float` in exponential notation with at least 9 significant digits to distinctively print all different `float` as different output. – chux - Reinstate Monica Apr 29 '21 at 14:33
  • @RD1153 Some compilers explicitly allow `union` to be used this way, such as GCC. However, you should be very aware of that such code is generally **not portable**. – Daniel Langr Apr 29 '21 at 15:12
  • @FrançoisAndrieux: Re “It means anything can happen”: That is not what “undefined behavior” means in the C++ standard. It means the standard imposes no requirements. Since the standard is one of only several or many things that affect the behavior of computer programs, the behavior is still affected by other things, which prevent “anything” from happening. – Eric Postpischil Apr 29 '21 at 17:13
  • @EricPostpischil I'm not sure I understand the distinction you are making. Doesn't UB mean that any behavior is permitted by the standard? If so, how is that different from "anything can happen"? – François Andrieux Apr 29 '21 at 17:48
  • @FrançoisAndrieux: The behavior of a compiler is not governed solely by a language standard. It has its own documentation, which specifies extensions it supports, which are often implemented by defining behavior that is undefined by the standard. If, by “undefined behavior,” the standard meant “anything could happen,” that would override other documentation. It does not. When there is behavior that is “undefined behavior” in the meaning of the standard, any applicable documentation of the compiler still applies… – Eric Postpischil Apr 29 '21 at 18:02
  • … The compiler is also governed by the operating system. The language standard does not override that. User programs cannot overwrite other user’s files just because there is “undefined behavior” in the user’s source code. The hardware the program runs on is generally subject to consumer product laws. The machine is required not to start a fire just because there is “undefined behavior” in the user’s source code. These are things. They are not permitted to happen. “Undefined behavior” **only** means the standard does not specify what happens. It does not mean any thing may happen… – Eric Postpischil Apr 29 '21 at 18:04
  • … In particular, the notion that “undefined behavior” means “anything can happen” is antithetical to the notion of extending the language. Compiler extension to languages work by specifying behavior that the language standard does not define. Programmers can only rely on compiler extensions because compilers are allowed to define the behavior—if the standard insisted that “anything can happen,” then it would not be possible to promise that an extension works. – Eric Postpischil Apr 29 '21 at 18:06
  • @EricPostpischil Ok, I understand what you are saying. But absent any information about the actual implementation being used, if someone were to ask what the behavior of a UB construct is, it is still accurate that the behavior might be anything. "anything can happen" is not the same as "the behavior is required to be unpredictable". If a compiler specifies an extension, whatever it specifies is a subset of "anything". It's true that the result of UB will be *something* in the set of all behaviors. A specific implementation can then narrow that range, possibly to a single behavior. – François Andrieux Apr 29 '21 at 18:16
  • ... Without any information on the implementation being used, the resulting behavior is the union of "whatever implementation A might do", "whatever B might do" ... "whatever [any implementation] might do" ... "whatever [any conceivable future implementation] might do" which is the set of all possible behavior. This set is what "anything" is in "anything can happen". Maybe its the term "anything" that bothers you. But I feel "anything possible can happen" is redundant. – François Andrieux Apr 29 '21 at 18:19
  • @FrançoisAndrieux: Re “it is still accurate that the behavior might be anything”: No, it is not accurate, because it is not true. I have listed several things that **cannot** happen, so the assertion that “the behavior might be anything“ is not a true statement. And it is not necessary to explain to somebody that implementation A might do this, implementation B might do that, and so on. It is merely necessary to say “undefined behavior” means the standard does not specify the behavior… – Eric Postpischil Apr 29 '21 at 18:42
  • @EricPostpischil If an implementation chose to set the computer on fire, it may violate local law but it would still be conforming. No behavior is not conforming, the set of conforming behavior is all behavior. – François Andrieux Apr 29 '21 at 18:44
  • You're right that it is technically sufficient to say "the standard does not specify a behavior", but it is not sufficient when trying to communicate the implications to a beginner. – François Andrieux Apr 29 '21 at 18:46
  • … One reason I push on this is a number of people push the notion that undefined behavior is prohibited behavior. It is not. Programmers are free to go into the areas that the standards do not define and make full use of whatever specifications do define those areas. Plenty of GCC’s built-ins are not defined by the standard but are fine to use, as long as you are happy sticking to GCC. Nested functions are not defined by the standard but are by GCC. When you use one of GCC’s built-ins, the statement “anything can happen” is not true. We know what will happen, and it is not anything. – Eric Postpischil Apr 29 '21 at 18:47
  • @FrançoisAndrieux: The implication “If an implementation chose to set the computer on fire, it may violate local law but it would still be conforming” does not imply an implementation can set the computer on fire. It is not a thing that can happen with a consumer product conforming to regulation. The statement “Anything can happen” is not a true statement. And I disagree telling a beginner the standard does not specify behavior is insufficient. Certainly it is the truth, and telling them something that is not true is not better. It is better to learn sooner that not everything is specified. – Eric Postpischil Apr 29 '21 at 18:49
  • If I construct a computer that is able set itself on fire, and I write a C++ implementation for it with which some UB triggers that feature, as pathological as the scenario may be this theoretical implementation is still conforming. Thank you for your perspective, but I will respectfully disagree with your interpretation, and I will respectfully disagree that the statement of "anything can happen" is incorrect. – François Andrieux Apr 29 '21 at 18:53

0 Answers0