19

別のプログラム内で使用される浮動小数点リテラルを出力するプログラムを作成しています。

元の float の精度を維持するには、何桁印刷する必要がありますか?

float24 * (log(2) / log(10)) = 7.2247199の精度は 10 進数なので、最初は 8 桁で十分だと思いました。しかし、運が悪いと、0.2247199有効数字 7 桁の左右に分散されるので、10 進数 9 桁を表示する必要があります。

私の分析は正しいですか?すべてのケースで 9 桁の 10 進数で十分ですか? のようにprintf("%.9g", x);

float をその値に必要な最小桁数の文字列に変換する標準関数はありますか?7 または 8 で十分な場合、不要な数字を出力しませんか?

注: 標準の C++ ではサポートされていないため、16 進浮動小数点リテラルは使用できません。

4

8 に答える 8

16

2 進数 -> 10 進数 -> 2 進数の往復で元の 2 進数値が復元されることを保証するために、IEEE 754では


The original binary value will be preserved by converting to decimal and back again using:[10]

    5 decimal digits for binary16
    9 decimal digits for binary32
    17 decimal digits for binary64
    36 decimal digits for binary128

For other binary formats the required number of decimal digits is

    1 + ceiling(p*log10(2)) 

where p is the number of significant bits in the binary format, e.g. 24 bits for binary32.

C では、これらの変換に使用できる関数は、snprintf() および strtof/strtod/strtold() です。

もちろん、場合によっては、さらに多くの桁数が役立つこともあります (いいえ、 snprintf() などの 10 進数変換ルーチンの実装によっては、常に「ノイズ」であるとは限りません)。たとえば、2 進分数の印刷を考えてみましょう。

于 2012-06-05T11:27:16.287 に答える
3

C99 に準拠する C ライブラリがある場合 (および float 型の基数が 2 の累乗である場合:)、printf書式文字%aは浮動小数点値を 16 進形式で精度を損なうことなく出力でき、ユーティリティは asscanfおよびstrodになります。それらを読むことができます。

于 2012-06-05T11:40:26.760 に答える
3

24 * (ログ (2) / ログ (10)) = 7.2247199

それは問題のかなり代表的なものです。有効桁数を 0.0000001 桁の精度で表現しても意味がありません。機械ではなく人間の利益のために数値をテキストに変換しています。あなたが書いた場合、人間はそれほど気にすることができず、はるかに好むでしょう。

24 * (ログ (2) / ログ (10)) = 7

8 桁の有効数字を表示しようとすると、ランダムなノイズ桁が生成されます。浮動小数点エラーが計算で蓄積されるため、ゼロ以外のオッズでは、7 はすでに多すぎます。とりわけ、合理的な測定単位を使用して数値を出力します。人々はミリメートル、グラム、ポンド、インチなどに興味があります。1 mm よりも正確に表現された窓のサイズを気にする建築家はいないでしょう。これほど正確なサイズの窓を約束する窓製造工場はありません。

最後になりましたが、プログラムに入力する数値の精度を無視することはできません。荷物を積んでいないヨーロッパツバメの速度を 7 桁まで測定することはできません。およそ秒速 11 メートルで、せいぜい 2 桁です。したがって、その速度で計算を実行し、有効桁数が多い結果を出力すると、そこにない精度を約束する無意味な結果が生成されます

于 2012-06-05T10:56:44.207 に答える
2

プログラムがコンピューターによって読み取られることを意図している場合、char*エイリアシングを使用するという単純なトリックを実行します。

  • エイリアスfloat*_char*
  • エイリアシングunsignedを介して(または符号なしの型が十分に大きい場合)にコピーしますchar*
  • unsigned値を出力します

デコードはプロセスを逆にするだけです(ほとんどのプラットフォームではダイレクトreinterpret_castを使用できます)。

于 2012-06-05T11:21:35.180 に答える
1

Javaで使用される浮動小数点から小数への変換では、小数点以下の桁数が、隣接する数値と区別するために必要な最小数(多かれ少なかれ)になることが保証されています。

ここからアルゴリズムをコピーできます。http://www.docjar.com/html/api/sun/misc/FloatingDecimal.java.htmlFloatingDecimal(float)コンストラクターとtoJavaFormatString()メソッド に注意してください。

于 2012-06-05T10:29:54.607 に答える
1

これらの論文 (以下を参照) を読むと、数値を変更せずに再解釈できるように (つまり、scanf によって) 10 進数の最小桁数を出力するアルゴリズムがあることがわかります。

このような数値が複数存在する可能性があるため、アルゴリズムは元の 2 進分数に最も近い小数も選択します (私は float 値と名付けました)。

C にそのような標準ライブラリがないのは残念です。

于 2012-08-14T12:52:01.787 に答える
0

使用できますsprintf。これがあなたの質問に正確に答えるかどうかはわかりませんが、とにかく、ここにサンプルコードがあります

#include <stdio.h>
int main( void )
{
float d_n = 123.45;
char s_cp[13] = { '\0' };
char s_cnp[4] = { '\0' };
/*
* with sprintf you need to make sure there's enough space
* declared in the array
*/
sprintf( s_cp, "%.2f", d_n );
printf( "%s\n", s_cp );
/*
* snprinft allows to control how much is read into array.
* it might have portable issues if you are not using C99
*/
snprintf( s_cnp, sizeof s_cnp - 1 , "%f", d_n );
printf( "%s\n", s_cnp );
getchar();
return 0;
}
/* output :
* 123.45
* 123
*/
于 2012-06-05T10:31:05.023 に答える
-1

のようなもので

def f(a):
    b=0
    while a != int(a): a*=2; b+=1
    return a, b

(これはPythonです)損失のない方法で仮数と指数を取得できるはずです。

Cでは、これはおそらく

struct float_decomp {
    float mantissa;
    int exponent;
}

struct float_decomp decomp(float x)
{
    struct float_decomp ret = { .mantissa = x, .exponent = 0};
    while x != floor(x) {
        ret.mantissa *= 2;
        ret.exponent += 1;
    }
    return ret;
}

ただし、すべての値をそのように表現できるわけではないことに注意してください。これはアイデアを提供する簡単なショットにすぎませんが、おそらく改善が必要です。

于 2012-06-05T10:58:29.087 に答える