1

IEEE-754 の単精度および倍精度の数値を base を持つ文字列に変換する必要がある場合について述べました10。使用可能な命令がありFXTRACTますが、数の計算式は次のとおりであるため、基数 2 の指数と仮数のみが提供されます。

value = (-1)^sign * 1.(mantissa) * 2^(exponent-bias)

特定の基数に対する対数の指示があれば、2 の基数の指数 - 式のバイアス部分を変更できますが、現在、どうすればよいかわかりません。整数への標準的な丸め変換も考えていましたが、正確な変換ができないため使用できないようです。それを行うための方法/基本的な原則を知っている人はいますか? 助けてください。

私はついに別の解決策を見つけました(それはJavaにあります)

{
    /* handling -infinity, +infinity and NaN, returns "" if 'f' isn't one of mentioned */
    String ret = "";
    if ((ret = getSpecialFloats(f)).length() != 0)
        return ret;
}
int num = Float.toRawIntBits(f);
int exponent = (int)(((num >> 23) & 0xFF)-127); //8bits, bias 127
int mantissa = num & 0x7FFFFF; //23bits

/* stores decimal exponent */
int decimalExponent = 0;
/* temporary value used for calculations */
int sideMultiplicator = 1;
for (; exponent > 0; exponent--) {
    /* In this loop I'm calculating the value of exponent. MAX(unsigned int) = 2^32-1, while exponent can be 2^127 pr st like that */
    sideMultiplicator *= 2;
    /* because of this, if top two bits of sideMultiplicator are set, we're getting closer to overflow and we need to save some value into decimalExponent*/
    if ((sideMultiplicator >> 30) != 0) {
        decimalExponent += 3;
        sideMultiplicator /= 1000;
    }
}
for(; exponent < 0; exponent++) {
    /* this loop does exactly same thing as the loop before, but vice versa (for exponent < 0, like 2^-3 and so on) */
    if ((sideMultiplicator & 1) != 0) {
        sideMultiplicator *= 10;
        decimalExponent--;
    }
    sideMultiplicator /= 2;
}

/* we know that value of float is:
 *  1.mantissa * 2^exponent * (-1)^sign */
/* that's why we need to store 1 in betweenResult (another temorary value) */
int betweenResult = sideMultiplicator;
for (int fraction = 2, bit = 0; bit < 23; bit++, fraction *= 2) {
    /* this loop is the most important one: it turns binary mantissa to real value by dividing what we got in exponent */
    if (((mantissa >> (22-bit)) & 1) == 1) {
        /* if mantissa[bit] is set, we need to divide whole number by fraction (fraction is 2^(bit+1) ) */
        while (sideMultiplicator % fraction > 0 && (betweenResult >> 28) == 0) {
            /* as we needed it before: if number gets near to overflow, store something in decimalExponent*/
            betweenResult *= 10;
            sideMultiplicator *= 10;
            decimalExponent--;
        }
        betweenResult += sideMultiplicator/fraction;
    }
}

/* small normalization turning numbers like 15700 in betweenResult into 157e2 (storing zero padding in decimalExponent variable)*/
while (betweenResult % 10 == 0) {
    betweenResult /= 10;
    decimalExponent++;
}
/* this method gets string in reqested notation (scientific, multiplication by ten or just normal)*/
return getExponentedString(betweenResult, decimalExponent);
4

3 に答える 3

7

浮動小数点数の書式設定はかなり簡単ではありません。たとえば、Dragon4 アルゴリズムを検索します (ここに 1 つの結果があります)。

非常素朴に、これを試すことができます:

  1. NaN と無限大を処理します。

  2. 記号を印刷します ( にチェックを入れ< 0ます)。これ以降、数値は正の実数であると仮定します。

  3. の場合>= 1は、切り捨てて使い慣れた整数形式を使用して整数部分を出力します。(浮動小数点ユニットを備えたハードウェアには、そのための機械語命令があるはずです。)

  4. 小数点記号を出力します。10 を掛け続けて、切り捨てられた整数の数字を表示します。

  5. 目的の精度に達したら停止します。最後の桁を正しく四捨五入することを考えてください。

于 2013-07-13T17:02:37.370 に答える
1

Kerrek SB の解決策は正しいです。ただし、ループなしで(またはループの数を減らして)より速く実行できます。小数部分を 10 の精度で掛けるだけです。数値または乗算を減らすと、浮動小数点型で計算を行う場合、累積誤差も減少します。正確な変換を行うには、より精度の高い浮動小数点型を使用する必要があります。

たとえば、0.1234567 を 5 桁の精度で変換したい場合は、数値に 10000 を掛けて int 部分を取得します。丸めが必要な場合は、100000 を掛けて最後の数値を丸めます。

于 2013-07-26T14:39:45.470 に答える