3

浮動小数点数を基数 10 から標準入力で読み込まれる別の基数に変換するためのカスタム コードがあります。float の浮動小数点の前の数字の別の基数への変換は、浮動小数点数を基数で割り、数値を逆に書き込むことによって実装されます。浮動小数点に続く桁の変換は、それらに基数を乗算し、浮動小数点の前の桁をこの一時的な結果に順番に書き込むことによって実装されます。

問題は、基数 10 の 0.8 などの一部の浮動小数点数がバイナリで有限表現を持たないという事実の犠牲者であることです (したがって、7.9999 と書かれています...)。したがって、 input 2.8、または 2 より大きく、.8 で終わる任意の入力 ( 2.83.84.8) の場合、基数 10 を離れても、(2.79999..., 3.79999..., 4.79999..) という出力が得られます。 .)。

問題は、これを修正するにはどうすればよいか、0.8 や 1.8 で同じ間違いを起こさないのはなぜですか?

コードは次のとおりです。

#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;
}
4

2 に答える 2

2

0.8 や 1.8 で同じ間違いを起こさないのはなぜですか?

そのような場合でも、に格納するときに結果を丸めていdoubleます。あなたが観察しているのは、丸めによって必要な答えが得られる場合があるということだけです。

どうすればこれを修正できますか?

doubleあなたがIEEE-754である (強い) 可能性では、約 16 桁の精度があります。

精度の桁数が少ないことに満足している場合は、基数 10 の結果を丸めることができます。

などの結果が得られたら、2.7999999桁数を減らすように丸めます。

于 2013-04-15T16:03:58.113 に答える
1

値を浮動小数点型に格納するとすぐに、元の値が失われます。この場合、いくつかの数値 (わずかに大きくなることで元の値を失うようなものと、小さくなることで元の値0.8を失うような他の数値など)があります。2.8

いずれにせよ、通常の解決策は、浮動小数点数を使用しない (固定小数点または文字列表現を使用する) か、表示中に小数点以下の桁数に丸めることです。

于 2013-04-15T16:01:12.693 に答える