You are here:

C++/Floating no comparison

Advertisement


Question
main()
{
float me = 1.1;
double you = 1.1;
if(me==you)
printf("I love U");
else
printf("I hate U");
}

I know that we have to take care in comparing floating point nos. I know that we will get output as " I hate U" but I am not sure that do we always gets the same output?
Is it that the condition is always false on all systems?


Answer
The problem is that you are not comparing like with like. You are comparing a lemon with a grapefruit (err, sorry that was the best I could come up with for a small and large version of similar fruit types!). Hence it depends on the values in question and the relative precision of float and double types in the C or C++ implementation you are using.

For example if you try your program with both the variables me and you set to a value of 0.25 then I would expect the result to be the true case and "I love U" is output. I would also expect this to be the case on all reasonable implementations of C or C++ as 0.25 is easily represented as a binary fraction in float or double precision (unless the precision is very, very limited to an extent it is not really usable).

Also I would expect the answer to be the true case and "I love U" is output if the types are both float or both double or both long double, as then the variables me and you will be represented to the same precision.

Finally I would expect the answer to be the true case and "I love U" is output if you built and ran you program using a C/C++ implementation in which the precision of both float and double were the same (e.g. they are both 32 bits). In this case float and double are effectively the same type under the covers. Note that this is not as unlikely as it seems. Maybe most systems have a double type that has more precision than float but many do not have a long double type that has more precision than a double and on such implementations double and long double will have the same precision.

If you are interested in the format of the three floating point type in C++ then you can use the std::numeric_limits class template in the C++ <limits> header to obtain such information. Similar information can be obtained in C from the C constants in the C <float.h> header. For example in C++ we could write a program such as:

#include <iostream> // for std::cout
#include <limits>   // for std::numeric_limits

int main()
{

   std::cout << "Float format:"
         << "\n          radix: "
         << std::numeric_limits<float>::radix
         << "\n         radix digits: "
         << std::numeric_limits<float>::digits
         << "\n       decimal digits: "
         << std::numeric_limits<float>::digits10
         << "\n       radix exponent: "
         << std::numeric_limits<float>::min_exponent
         << " to "
         << std::numeric_limits<float>::max_exponent
         << "\n     decimal exponent: "
         << std::numeric_limits<float>::min_exponent10
         << " to "
         << std::numeric_limits<float>::max_exponent10
         << '\n'
         ;

   std::cout << "\nDouble format:"
         << "\n          radix: "
         << std::numeric_limits<double>::radix
         << "\n         radix digits: "
         << std::numeric_limits<double>::digits
         << "\n       decimal digits: "
         << std::numeric_limits<double>::digits10
         << "\n       radix exponent: "
         << std::numeric_limits<double>::min_exponent
         << " to "
         << std::numeric_limits<double>::max_exponent
         << "\n     decimal exponent: "
         << std::numeric_limits<double>::min_exponent10
         << " to "
         << std::numeric_limits<double>::max_exponent10
         << '\n'
         ;

   std::cout << "\nLong double format:"
         << "\n          radix: "
         << std::numeric_limits<long double>::radix
         << "\n         radix digits: "
         << std::numeric_limits<long double>::digits
         << "\n       decimal digits: "
         << std::numeric_limits<long double>::digits10
         << "\n       radix exponent: "
         << std::numeric_limits<long double>::min_exponent
         << " to "
         << std::numeric_limits<long double>::max_exponent
         << "\n     decimal exponent: "
         << std::numeric_limits<long double>::min_exponent10
         << " to "
         << std::numeric_limits<long double>::max_exponent10
         << '\n'
         ;
}

On my 32-bit Visual C++ 8.0 (a.k.a. 2005) compiler it produced the following output:

Float format:
         radix: 2
        radix digits: 24
      decimal digits: 6
      radix exponent: -125 to 128
    decimal exponent: -37 to 38

Double format:
         radix: 2
        radix digits: 53
      decimal digits: 15
      radix exponent: -1021 to 1024
    decimal exponent: -307 to 308

Long double format:
         radix: 2
        radix digits: 53
      decimal digits: 15
      radix exponent: -1021 to 1024
    decimal exponent: -307 to 308

As you can see for this compiler double has more precision than float but long double has the same precision as double. On the other hand g++ 4.0.1 on 64-bit x64 SuSE Linux produced:

Float format:
         radix: 2
        radix digits: 24
      decimal digits: 6
      radix exponent: -125 to 128
    decimal exponent: -37 to 38

Double format:
         radix: 2
        radix digits: 53
      decimal digits: 15
      radix exponent: -1021 to 1024
    decimal exponent: -307 to 308

Long double format:
         radix: 2
        radix digits: 64
      decimal digits: 18
      radix exponent: -16381 to 16384
    decimal exponent: -4931 to 4932


In this case float has less precision than double which has less precision than long double.

So we can explore what happens when we have some implementations with the same precision and others with different precision if we modify your original program to use double and long double and build using both the above mentioned compilers. The revised program is as follows (note I also converted to C++ style IOStreams for the output):

int main()
{
   double me = 1.1;

   long double you = 1.1L;

   if ( me==you )
   {
       std::cout << "I love U\n";
   }
   else
   {
       std::cout << "I hate U\n";
   }
}

Notice that I have explicitly specified that the long double initialiser value is a long double value by the L suffix. Without it both me and you are initialised with only double precision for 1.1 and so are always equal.

Strictly speaking you should have specified the 1.1 for the float value in the original program as a float literal rather than a double literal by suffixing it with an F. Not doing so caused my Visual C++ compiler to issue a value truncation warning for the 1.1 initialisation value but not for the 0.25 value - which in fact was a good indicator of potential trouble!

Any who, back to the revised program. Building it with my Visual C++ 32-bit compiler gave the output "I love U" as the precision of double and long double are the same for this compiler. On the other hand building using the g++ 64-bit compiler and running it gave the output "I hate U" because the precision of double and long double differ for this compiler.

Hope this has been of use to you.  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.