Thread: A double variable equals one, it also doesn't equal one.

  1. #1
    Registered User
    Join Date
    Feb 2009
    Posts
    68

    A double variable equals one, it also doesn't equal one.

    I have this code:

    Code:
    #include <stdio.h>
    
    int main()
    {
    	double temp;
    	temp = 0;
    	temp = temp + .6;
    	temp = temp + .3;
    	temp = temp + .1;
    	printf("%lf\n", temp);
    	if(temp != 1)
    	{
    		printf("Improper matrix!  Please use another.\n");
    	}
    	return(0);
    }
    I'm sure most people know why it prints "Improper matrix! Please use another."

    I have no idea what to search for, so I guess I'll ask you guys/girls why it does this (besides the fact that .6+.3+.1 != 1).

    Yesterday when I was working on it, it printed it when I was using if(temp == 1), today it won't.

    Edit: Apparently using %.999lf prints:

    .9999999999999998889776975374843459576368331909179 687500..0 How interesting. Is there a way to get around this?
    Last edited by madmax2006; 02-14-2010 at 07:29 PM.

  2. #2
    Registered User
    Join Date
    Feb 2010
    Posts
    12
    When you use floats/doubles, there's an error. In this case, although the number appears as 1.00000 in printf, it's just rounded from 0.99999999 (at least on my computer, I believe in other machines, it may be rounded from 1.0000000001, for example).
    You can't really use it to compare.
    You can, however, use the math library and round the double, so that it becomes an exact number. I'd recommend you round it to a long, with the function lround().
    The code would stay like this:

    Code:
    #include <stdio.h>
    #include <math.h>
    
    int main()
    {
    	double temp;
            temp = 0;
    	temp = temp + .6;
    	temp = temp + .3;
    	temp = temp + .1;
    	printf("%lf\n", temp);
    	if(lround(temp) != 1)
    	{
    		printf("Improper matrix!  Please use another.\n");
    	}
    	return(0);
    }

  3. #3
    Registered User
    Join Date
    Feb 2009
    Posts
    68
    It's going to be terribly annoying to have to deal with that. I thought the point of double was to have accuracy. (I'm not flaming you)
    I guess everything has problems =\

    I put #include <math.h> in the header and I'm still getting an error...

    Thanks for the help mang

  4. #4
    Registered User
    Join Date
    Feb 2010
    Posts
    12
    What's the error that you have?
    It is terribly annoying, that's a fact xD
    If you're using linux, don't forget to include the math library in the compiler line.
    To compile it using gcc, would be something like this:
    gcc -lm -o test test.c
    (test.c = source file)
    If you're using another compiler, search for how to enable the math library with it.

  5. #5
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by madmax2006 View Post
    It's going to be terribly annoying to have to deal with that.
    Perhaps a little, but if you use floating point for a while you'll get used to it and know what the good methods of approximate comparison are
    I thought the point of double was to have accuracy.
    That's just it, the way they work does give you about the most accuracy possible! The problem is that you're expecting it to give especially accurate results for base 10 values, but IEEE floating point types don't use base 10, they use base 2.

    The platforms out there that have base 10 floating point types require 4 bits to store each digit, which as you know could store 16 possible values, and 6 of those are unusable. That's (37.5%) wastage - OUCH!
    What's more they still don't help you with calculations as simple as 1.0 / 3.0. Now if they used base 3 then that 1.0 / 3.0 work be exactly representable, but you'd have problems with something as simple as 1.0 / 2.0! In other words, no matter what base they use, they are going to fail to represent even some of the simplest fractions exactly. Picking a different base just makes different cases worse. So the best thing to do is for them to use a base that is a power of two to waste the least space. Funnily enough a base of exactly two is also the simplest the implement, and you get at least as many decimal places as you would in base 10 since no bits are wasted. As an example, using just 10 bits you can represent numbers with 3 decimal digits if you store the number using binary, but if you use BCD (base 10) you can only store 2 decimal digits.


    No matter what, you will always need to compare floating points using a method that checks for approximately equal. The only way around it is to use a custom 'fraction' data type instead.
    Last edited by iMalc; 02-15-2010 at 01:45 AM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  6. #6

  7. #7
    Registered User
    Join Date
    Jul 2009
    Posts
    36
    Quote Originally Posted by madmax2006 View Post
    Edit: Apparently using %.999lf prints:

    .9999999999999998889776975374843459576368331909179 687500..0 How interesting.
    There are 53 non-zero digits here, which not coincidentally is the number of bits in the significand of a double. In binary, this is '0.' followed by 53 1s: 0.111111111111111111111111111111111111111111111111 11111. This is equivalent to the fraction (2^53-1)/2^53.

    BTW, are you using gcc on Linux? Not too many compilers will let you print all those digits -- gcc is one of them (see my article Print Precision of Dyadic Fractions Varies by Language - Exploring Binary .)

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by DoctorBinary View Post
    There are 53 non-zero digits here, which not coincidentally is the number of bits in the significand of a double.
    A binary digit is not the same as a decimal digit. I think this is just a freakish coincidence.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    Registered User
    Join Date
    Jul 2009
    Posts
    36
    Quote Originally Posted by brewbuck View Post
    A binary digit is not the same as a decimal digit. I think this is just a freakish coincidence.
    It's not a coincidence. A binary fraction (i.e. 0 < f < 1) has as many decimal digits as bits. Try any binary fraction you like. Here are just two examples:

    0.11001111 = 0.80859375
    0.1100101010101 = 0.7916259765625

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by madmax2006 View Post
    I thought the point of double was to have accuracy.
    On the contrary, the format is specifically designed to represent a vast range of approximations. If you want real accuracy, use integral fractions.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. No Match For Operator+ ???????
    By Paul22000 in forum C++ Programming
    Replies: 24
    Last Post: 05-14-2008, 10:53 AM
  2. expected primary expression
    By mju4t in forum C Programming
    Replies: 2
    Last Post: 03-27-2007, 06:59 PM
  3. functions and passing data
    By redmondtab in forum C Programming
    Replies: 41
    Last Post: 09-21-2006, 12:04 PM
  4. Help with multi function progam
    By WackoWolf in forum C Programming
    Replies: 22
    Last Post: 10-13-2005, 02:56 AM
  5. Variable Allocation in a simple operating system
    By awkeller in forum C Programming
    Replies: 1
    Last Post: 12-08-2001, 02:26 PM