Skip to main content
GameDev.net gamedev.net
🔒 Locked

doubles in C!!!!!!!!

Started by Yohomyth Dec 20, 2005 at 3:05 PM 25 replies 4.4k views
Original Post
Yohomyth
Yohomyth
whenever i pass 1.25 into a function as a parameter, it turns into 1.249999999! is there a way to prevent this?
------------------------------------------------------------"Many combilations elizagerth. I hope you see my particles." - Senor Cardgage
Fruny
Fruny
1.25 should be perfectly representable by a double.

But in general, no. Numbers like, for example, 0.1 have no exact representation in binary, just like 1/3 has no exact representation in decimal.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Promit
Promit
Make sure you're not passing 1.25f if it's a double.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Yohomyth
Yohomyth
i think Fruny is right. i've tried 1.25, 1.250, 1.25f, 1.250f, even 1.25d out of curiosity, but that caused a compiler error.
------------------------------------------------------------"Many combilations elizagerth. I hope you see my particles." - Senor Cardgage
Alpha_ProgDes
Alpha_ProgDes
Quote:
Original post by Yohomyth
i think Fruny is right. i've tried 1.25, 1.250, 1.25f, 1.250f, even 1.25d out of curiosity, but that caused a compiler error.

i believe d and i are for integers.
f for floats
d for doubles
o for octals
h for hexadecimal (?)
s for character strings

Beginner in Game Development?  Read here. And read here.  
M2tM
M2tM
I believe there is actually an issue with binary numbers representing decimals of certain values (which means that they become approximated). The problem is not with the type of floating point type you are using, but with the binary approximation of the values of floating point numbers in general.

If you -require- absolute accuracy to a certain point, you can look at fixed point numbers
_____"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk
M2tM
M2tM
Check out this interesting tidbit. Read the section "A word about narrowing conversions"

I don't think it applys here at all, but it is interesting to note:

"a double constant can be implicitly (i.e., silently) converted to a float constant, even if doing so loses precision"

read the context surrounding that though.
_____"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk
nmi
nmi
Quote:
Original post by Yohomyth
whenever i pass 1.25 into a function as a parameter, it turns into 1.249999999! is there a way to prevent this?


Did you use printf to check this or your debugger ? Can you post some code ?

Since 1.25 in decimal is 1.01 in binary, there should be no problem to store that number, as Fruny already mentioned. Also converting between float and double should keep that number.

Maybe the conversion from decimal to binary during compilation may be wrong. Or the conversion from binary to decimal for displaying the number is wrong (i.e. in your debugger or in printf).
Yohomyth
Yohomyth
Quote:
Or the conversion from binary to decimal for displaying the number is wrong (i.e. in your debugger or in printf)

if this is true, then there may be something wrong with my code, but there may not be. after passing 1.25 through the function, the debugger says it's 1.2499999999. but i have a function that converts a double into a string to store it in an INI file, and it gets the same result as the debugger. but if this imperfection hasn't affected anything before, i don't see why it would after it's changed to a string and back.
------------------------------------------------------------"Many combilations elizagerth. I hope you see my particles." - Senor Cardgage
ZQJ
ZQJ
Well, presumably the debugger and your string conversion both use some routine equivalent to printf("%f", 1.25). I think the problem is not that your value isn't equal to 1.25, but that the printf routine is losing precision something like this:

Initially: 1.25 = 1.01b
First digit found to be 1, so:
1.25 - 1 = 0.25
1.01b - 1.00b = 0.01b

Second digit found to be 2
0.25 - 0.20 = 0.05
BUT in binary 0.20 is not exactly representable - it's 0.0011001100110011 etc.)
So presumably the rounding mechanism is rounding the last digit down in this case producing a number just below 0.05 instead of one just above it, giving you your .49999999. Way to solve this: write a better printf :) or possibly change the CPU rounding mode using C99's fesetround.
Yohomyth
Yohomyth
i'm not using printf
------------------------------------------------------------"Many combilations elizagerth. I hope you see my particles." - Senor Cardgage
ZQJ
ZQJ
Quote:
Original post by Yohomyth
i'm not using printf

Quote:
Original post by ZQJ
some routine equivalent to printf("%f", 1.25).

I didn't say you were. I'm assuming iostreams, ftoa and whatever else you can dig up in the C/C++ runtime library (and very probably FormatMessage as well) work the same way.
nmi
nmi
Quote:
Original post by ZQJ
Second digit found to be 2
0.25 - 0.20 = 0.05
BUT in binary 0.20 is not exactly representable - it's 0.0011001100110011 etc.)


Very good explanation, seems resonable to me.
But it does not explain why 1.25 is display previously. It should have been 1.24999... in both cases.

Yohomyth, did you check if the binary representation of your number changes ?
Ravyne
Ravyne
Regardless of whether or not 1.25 is exactly representable or not, the point is moot. The fact is that there will be numbers which are not perectly representable, its a fact of life with the IEEE formats. Instead of trying to "fix" this "problem" with 1.25, you should instead be reworking any assumptions you made about how accurately floating-point numbers are stored.
throw table_exception("(? ???)? ? ???");
Yohomyth
Yohomyth
it just pushes 0x3FF40000 or something onto the stack. it doesn't change. the debugger displays it as 1.2499999999. my converter also makes it turn out the same way.

str_t WrReaVal( real_t val, int_t dig ){	str_t  ret;	real_t test;	real_t larg;	int_t  len;	int_t  c;	int_t  cur;	int_t  i;	bool_t neg;	// negative?	if( val < 0 )	{		neg = TRUE;		val *= -1;	}		// not negative	else neg = FALSE;	// count left digits	if( val > 0.0 )	{		// find largest digit		test = 1;		while( test <= val ) test *= 10;		test /= 10;		larg = test;		// get string length		if( larg >= 1 )			len = Zeros( test ) + 3 + Larger( 1, dig );		else len = ( 3 + Larger( 1, dig ) );	}	// negative?	if( neg ) len++;	// allocate string	ret = MemAlloc( len );	c = 0;	// negative?	if( neg )	{		ret[0] = '-';		c++;	}	// above	while( larg >= 1 )	{		ret[c] = '0' + ( cur = (int_t) val / (int_t) larg );		val -= (real_t) cur * larg;		c++;		larg /= 10;	}	// decimal	ret[c] = '.';	c++;	// zero right digits?	if( dig == 0 )	{		ret[c] = '0';		c++;	}	// right digits	else	{		for( i = 0; i < dig; i++ )		{			ret[c] = '0' + ( cur = (int_t)( val / larg ) );			val -= (real_t) cur * larg;			c++;			larg /= 10;		}	}	// return	ret[c] = 0;	return ret;}


val is a real_t (which is double in this case) and is the number that gets converted. this probably isn't the best converter, but i didn't have much time to make it. dig is the number of digits to the right of the decimal that will be displayed.
------------------------------------------------------------"Many combilations elizagerth. I hope you see my particles." - Senor Cardgage
Conner McCloud
Conner McCloud
Quote:
Original post by Yohomyth
it just pushes 0x3FF40000 or something onto the stack. it doesn't change. the debugger displays it as 1.2499999999. my converter also makes it turn out the same way.

(1) Have you considered ZQJs suggestion? It seems extremely likely. Step through your main loop, and see if at any point the subtraction doesn't misbehave.

(2) C provides a few ways of doing this already...snprintf comes immediately to mind

(3) Comments are your friend, but not useless ones like "//negative?" followed by "if(negative)"

CM
Yohomyth
Yohomyth
1.I'm not using iostreams, or ftoa, or anything like that.

3.Sorry about that. I'm kinda obsessive about putting comments before every tiny section of code.
------------------------------------------------------------"Many combilations elizagerth. I hope you see my particles." - Senor Cardgage
JohnBolton
JohnBolton
1.25 and 1.249999999 are the same number. There is nothing wrong and nothing to fix. You just have to get used to it.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Fruny
Fruny
Are you sure it uses 0x3FF40000 ?

00111111 11110100 00000000 00000000 01111111 11101000000000000000000s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmmsign bit:           : 0 (positive)exponent:           : 01111111  == 127float exponent bias : 127actual exponent     : 127 - 127 == 0mantissa:           :   11101000000000000000000normalized mantissa : 1.11101000000000000000000mantissa            : 1 + 1/2 + 1/4 + 1/8 + 1/32 = 1.90625f = (-1)<sup>0</sup>*2<sup>0</sup>*1.90625 = 1.90625


I would have expected 0x3FC00000
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.