The following solution was inspired by the comment that Millimoose made - so thanks!
Read the input as a string. Strip any trailing zeros to the right of the decimal. Remove the decimal. Convert to int.
Note - this works particularly well because it circumvents the problem of finite precision in the representation of a decimal - a problem you will always encounter because you start with a floating point number that is human-readable. However, if you need a function that is passed an inexact representation of a floating point number, the best you can hope for is to use your method, and stop the loop after a finite number of iterations.
Even better would be to subtract, and multiply the remainder by 10. In that way your loop can always terminate (this is how number to string representation functions work). If you intend to convert to an integer at the end you need to make sure you don't get overflow. If you collect the numbers into another string you don't have to worry about overflow.
In short - as stated the problem does not have an exact solution, but the above should give you some insights into approaches to take.
EDIT here is some code that does what I described (different approaches - and demonstrating the overflow problem):
#include <iostream>
#include <math.h>
int main(void){
double d=0;
char buffer[100];
char buf2[100];
long int i,j;
std::cout<<"Enter a double : ";
fgets(buffer, 100, stdin);
strncpy(buf2, buffer, 100);
// method 1: use string manipulation to get the answer
i = (int)(strstr(buffer, ".") - buffer);
if (i >= 0)
{
j = strlen(buffer)-1;
while(buffer[j-1]=='0')
{
j--;
}
for(; i<j; i++)
{
buffer[i]=buffer[i+1];
}
buffer[j-1]='\0'; // trim it
}
std::cout << "The integer representation of that string is " << buffer << "\n";
// method 2: use a finite length conversion
sscanf(buf2, "%lf", &d);
printf("The string converted to double is %lf\n", d);
j = (long int)d;
sprintf(buffer, "%ld", j);
int k;
k = strlen(buffer);
d -= j;
for(i=0; i<20; i++)
{
d *= 10;
if (fabs(d) > 0)
{
sprintf(buffer + k, "%01d", (int)d);
k++;
printf("i = %ld; j is now %ld; d is %lf\n", i, j, d);
j = 10 * j + (int) d;
d -= (int) d;
}
else break;
}
printf("after conversion, the number is %ld\n", j);
printf("using the string method, it is %s\n", buffer);
}
Here is sample output:
Enter a double : 123.456001
The integer representation of that string is 123456001
The string converted to double is 123.456001
i = 0; j is now 123; d is 4.560010
i = 1; j is now 1234; d is 5.600100
i = 2; j is now 12345; d is 6.001000
i = 3; j is now 123456; d is 0.010000
i = 4; j is now 1234560; d is 0.100000
i = 5; j is now 12345600; d is 1.000000
i = 6; j is now 123456001; d is 0.000000
i = 7; j is now 1234560010; d is 0.000000
i = 8; j is now 12345600100; d is 0.000001
i = 9; j is now 123456001000; d is 0.000005
i = 10; j is now 1234560010000; d is 0.000054
i = 11; j is now 12345600100000; d is 0.000545
i = 12; j is now 123456001000000; d is 0.005448
i = 13; j is now 1234560010000000; d is 0.054479
i = 14; j is now 12345600100000000; d is 0.544787
i = 15; j is now 123456001000000000; d is 5.447873
i = 16; j is now 1234560010000000005; d is 4.478733
i = 17; j is now -6101143973709551562; d is 4.787326
i = 18; j is now -5671207515966860768; d is 7.873264
i = 19; j is now -1371842938539952825; d is 8.732636
after conversion, the number is 4728314688310023374
using the string method, it is 12345600100000000054478
As you can see from this, there were some "rounding error bits" stuck way to the right; as I was multiplying and subtracting, these bits eventually became visible. This loop could go on forever. I stopped it at 20, which was actually too many - j
had already overflowed by this time. I think it shows you what's going on exactly, though.
You have to define the precision with which you want your answer, or you cannot solve this problem in general terms. If you truly need more than 10 or so digits I recommend that you use a string based approach, or things like BigDecimal.
PS I apologize for mixing C and C++. I never was much of a C++ person, so this comes more naturally on a Saturday morning.
PS2: Modifying the above code a little bit, I could find the full decimal representation of the two numbers you mentioned. It turns out that
1.12 --> 112000000000000010658141036401502788066864013671875
In other words, the actual representation is slightly larger than 1.12
. On the other hand,
1.123 --> 11229999999999999982236431605997495353221893310546875
As you can see, it is slightly smaller. This is why your loop never terminates, since you are checking whether d - (int) d > 0.0
. As the int
conversion rounds down, this condition is always true.