 |
 |
 |
 |
| Programming & Packaging A place to discuss programming and packaging. |

24th August 2009, 07:15 PM
|
|
Registered User
|
|
Join Date: Jul 2009
Posts: 19

|
|
|
g++: trouble converting double to int
When casting a double into an int certain numbers will be decremented by one. I didn't see any pattern to the numbers that were properly converted and those that weren't.
for example:
Code:
#include iostream
using namespace std
void main()
{
double n=574.05;
n=n*100;
cout<<n<<endl;
int m=(int)n;
cout<<m<<endl;
cout<<n<<endl;
return 0;
}
returns:
This happens on both windows 7 rc1 (64bit) and fedora 11 (32bit). However, when I used visual studio.net 2003 at school to compile my code, I did not get this error. I just install gcc-c++ on fedora last night to test it, so I imagine I'm using the latest version.
This is driving me crazy. None of the visual-crap sweets work right in windows 7, so that's not an option at home. If anyone has a solution, please let me know.
Thanks.
|

24th August 2009, 07:53 PM
|
 |
Registered User
|
|
Join Date: Jul 2009
Location: London,England
Posts: 1,095

|
|
Try the following in windows, does it produce the same output? This is on 32bit gcc, and as you can see the internal representation is 57404.999999..., windows compilere may be representing it internally as 57405.000000...
Code:
#include <iostream>
using namespace std;
int main()
{
double n=574.05;
n=n*100;
cout.precision(18);
cout<<n<<endl;
int m=(int)n;
cout<<m<<endl;
cout<<n<<endl;
return 0;
}
Code:
$ g++ -o gcctest gcctest.cpp
$ ./gcctest
57404.9999999999927
57404
57404.9999999999927
|

24th August 2009, 08:02 PM
|
|
Registered User
|
|
Join Date: Jul 2009
Posts: 19

|
|
|
yep, same output.
After posting this thread I finally got visual c++ working. Compiling it with that results in the same output.
|

24th August 2009, 08:04 PM
|
 |
Registered User
|
|
Join Date: Aug 2007
Location: Switzerland
Posts: 479

|
|
|
I guess it might be some rounding error, I have the same outputs as you...
however, the problem disappears if you set n to e.g. 574.10, or to 574.005, and multiply by 1000.
but this is not an satisfying answer (neither for you nor me). I'll keep looking into this.
EDIT: just saw the post by gödel. that would explain some things...
Last edited by newiLuvatar; 24th August 2009 at 08:07 PM.
|

24th August 2009, 08:52 PM
|
|
Registered User
|
|
Join Date: Feb 2006
Posts: 780

|
|
|
It's more of representation failure.
You've hit a value that has trouble being represented in binary. The (implementor of the) binary representation may choose an adjacent representation that comes closer to the actual value.
The following notion provides some of the freedom:
0.9999999 (infinitely repeating 9's) = 1
'=' means exactly, not approximately.
David
|

25th August 2009, 04:27 AM
|
|
Registered User
|
|
Join Date: Jul 2009
Posts: 19

|
|
Thanks for the help. 
That explains it.
|

25th August 2009, 07:39 AM
|
|
Clueless in a Cuckooland
|
|
Join Date: Mar 2006
Location: Here now, elsewhere tomorrow.
Posts: 3,929

|
|
Here's something fun for you:
Code:
#include <stdio.h>
int main(void) {
double n = 574.05;
int m;
printf("%.10lf\n", n * 100);
n = n * 100;
printf("%.10lf\n", n);
m = (int) n;
printf("%d\n", m);
return 0;
}
Code:
gcc -o castint castint.c
./castint
57405.0000000000
57405.0000000000
57404
Last edited by pete_1967; 25th August 2009 at 08:00 AM.
|

25th August 2009, 10:00 AM
|
 |
Registered User
|
|
Join Date: Jul 2009
Location: London,England
Posts: 1,095

|
|
with full precision
Code:
$ cat castint.c
#include <stdio.h>
int main(void) {
double n = 574.05;
int m;
printf("%.14lf\n", n * 100);
n = n * 100;
printf("%.14lf\n", n);
m = (int) n;
printf("%d\n", m);
return 0;
}
$ gcc -o castint castint.c
$ ./castint
57404.99999999999272
57404.99999999999272
57404
|

25th August 2009, 11:07 AM
|
|
Clueless in a Cuckooland
|
|
Join Date: Mar 2006
Location: Here now, elsewhere tomorrow.
Posts: 3,929

|
|
Quote:
Originally Posted by Gödel
with full precision
Code:
$ cat castint.c
#include <stdio.h>
int main(void) {
double n = 574.05;
int m;
printf("%.14lf\n", n * 100);
n = n * 100;
printf("%.14lf\n", n);
m = (int) n;
printf("%d\n", m);
return 0;
}
$ gcc -o castint castint.c
$ ./castint
57404.99999999999272
57404.99999999999272
57404
|
Spoilsport.
|

25th August 2009, 12:02 PM
|
 |
Registered User
|
|
Join Date: Jul 2009
Location: London,England
Posts: 1,095

|
|
sorry
The thing that has not been resolved is why Visual Studio .NET 2003 "at school" rounded to 57405, which may be due to the compiler representing the double differently to the other compilers, but that sounds unlikely.
|

25th August 2009, 03:47 PM
|
|
Registered User
|
|
Join Date: Jul 2009
Posts: 19

|
|
Quote:
Originally Posted by Gödel
sorry
The thing that has not been resolved is why Visual Studio .NET 2003 "at school" rounded to 57405, which may be due to the compiler representing the double differently to the other compilers, but that sounds unlikely.
|
Since Visual C++ compiled it the same way as g+, I'm now thinking that I may have fudged my testing, as I was in a hurry. I'll look more into it tomorrow when I go back, run more code and see for sure.
|

25th August 2009, 03:57 PM
|
|
Registered User
|
|
Join Date: Feb 2006
Posts: 780

|
|
Quote:
Originally Posted by Gödel
sorry
The thing that has not been resolved is why Visual Studio .NET 2003 "at school" rounded to 57405, which may be due to the compiler representing the double differently to the other compilers, but that sounds unlikely.
|
Were the results different than on another platform using the same compiler?
Anyway:
3.9.1-8
... The value representation of floating-point types is implementation-defined. ...
David
|

25th August 2009, 08:36 PM
|
 |
Registered User
|
|
Join Date: Jul 2009
Location: London,England
Posts: 1,095

|
|
The irony is that 57405 can be represented exactly by a double, at least with gcc, you can see that by running the following code:
Code:
#include <iostream>
using namespace std;
int main()
{
double n=574.05*100;
cout.precision(18);
cout<<"n = 574.05*100 = "<<n<<endl;
cout<<"(int)n = "<<(int)n<<endl;
(*(long long*)&n)++;
cout<<"next double is "<<n<<endl;
cout<<"(int)n = "<<(int)n<<endl;
(*(long long*)&n)++;
cout<<"next double is "<<n<<endl;
cout<<"(int)n = "<<(int)n<<endl;
return 0;
}
Code:
$ g++ -o gcctest gcctest.cpp -Wall
$ ./gcctest
n = 574.05*100 = 57404.9999999999927
(int)n = 57404
next double is 57405
(int)n = 57405
next double is 57405.0000000000073
(int)n = 57405
The successive doubles are obtained by reinterpreting the 64bit pattern for a double as a 64bit int (long long) and incrementing by 1 (bit), see http://www.cygnus-software.com/paper...ringfloats.htm
So maybe the .NET 2003 compiler does some clever trickery to make the answer exact when necessary (which sounds unlikely)
|

25th August 2009, 08:52 PM
|
|
Registered User
|
|
Join Date: Feb 2006
Posts: 780

|
|
Quote:
Originally Posted by Gödel
The irony is that 57405 can be represented exactly by a double...
|
That's not the issue.
Quote:
Originally Posted by Gödel
Code:
// ...
double n=574.05*100; // ...
|
The literal 574.05 can be represented exactly in base-10, as we clearly see. This is interpreted as a double, before multiplying by 100. While interpreting as a double it goes to base-2 encoding which can't exactly represent the 0.05 part since 0.05 equals 1/20 while 20 is not a (whole) power of 2.
From aforementioned wiki page: "In base-2 only rationals with denominators that are powers of 2 (such as 1/2 or 3/16) are terminating."
David
|
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
Current GMT-time: 21:04 (Friday, 24-05-2013)
|
|
 |
 |
 |
 |
|
|