I have a custom code for converting a floating-point number from base 10, to another base which is read in on the standard input. Conversion to another base of the digits before the floating point of the float is implemented by dividing it with the base, and writing the numbers backwards. Conversion of the digits following the floating point is implemented by multiplying them by the base, and writing the digits before the floating point in this temporary result sequentially.
The problem is that I am a victim of the fact that some floating point numbers such as 0.8 in base 10 do not have a finite representation in binary (so they're written as 7.9999...). Hence, for input 2.8, or any input that is larger than 2, and ends in .8, (2.8, 3.8, 4.8) even when I leave the base 10, I get outputs: (2.79999..., 3.79999..., 4.79999...).
The question is: how do I fix this and why don't I get the same mistake for 0.8 or 1.8?
Here is the code:
#include <iostream>
using namespace std;
void printInt(int *a,int k,int base)
{
if (base<10){
for (int i=k-1;i>=0;i--)
cout << a[i];
}else{
for (int i=k-1;i>=0;i--)
{
if (a[i]<10)
cout<<a[i];
else if (a[i]==10)
cout<<"A";
else if (a[i]==11)
cout<<"B";
else if (a[i]==12)
cout<<"C";
else if (a[i]==13)
cout<<"D";
else if (a[i]==14)
cout<<"E";
else cout<<"F";
}
}
}
void printRem(int *a,int k,int base)
{
if (base<10)
{
for(int i=0;i<k;i++){
cout<<a[i];
}
}else{
for(int i=0;i<k;i++)
{
if (a[i]<10)
cout<<a[i];
else if (a[i]==10)
cout<<"A";
else if (a[i]==11)
cout<<"B";
else if (a[i]==12)
cout<<"C";
else if (a[i]==13)
cout<<"D";
else if (a[i]==14)
cout<<"E";
else cout<<"F";
}
}
}
int main ()
{
double n;
int base;
cin>>n;
cin>>base;
int *whole,*rem,numWhole,numRem;
whole=NULL;
numWhole=0;
rem=NULL;
numRem=0;
double floatPart= n - (int)n;
int intPart=(int)n;
while (intPart!=0)
{
int *temp=new int[numWhole+1];
int remainder;
remainder=intPart%base;
intPart=intPart/base;
if (whole!=NULL)
for (int i=0;i<numWhole;i++)
temp[i]=whole[i];
delete [] whole;
temp[numWhole] = remainder;
whole=temp;
numWhole++;
}
while (floatPart!=0)
{
int *temp=new int[numRem+1];
double nov;
nov=floatPart*base;
if (rem!=NULL)
for (int i=0;i<numRem;i++)
temp[i]=rem[i];
temp[numRem]=(int)nov;
numRem+=1;
delete [] rem;
rem=temp;
floatPart=nov-int(nov);
if (numRem==10)
break;
}
printInt(whole,numWhole,base);
if (rem!=NULL) cout<<".";
printRem(rem,numRem,base);
cout<<endl;
cin >> n;
return 0;
}
why don't I get the same mistake for 0.8 or 1.8?
In those cases, you are still rounding the result when you store to double. All you are observing is that the rounding sometimes gives you the answer you want.
how do I fix this?
In the (strong) likelihood that your double is IEEE-754, it has about 16 digits of accuracy.
If you are content with fewer digits of accuracy, you can round your base 10 result.
When you get any result, such as 2.7999999, round it to fewer digits.
As soon as you store the value in a floating point type, you lose the original value. In this case some number (like 0.8 lose the original value by becoming slightly larger while other numbers such as 2.8 lose the original value by becoming smaller.
In any case the normal solution is to either not use floating point numbers (using either fixed point or string representation), or during display to round to a number of digits after the decimal point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With