3

もともと、次のコードを使用して、常に小数点以下2桁の浮動小数点数でsprintfを使用していました。

static void MyFunc(char* buffer, const float percentage)
{
    sprintf(buffer, "%.2f", percentage);
}

渡されたパーセンテージ値の 1 つは 0x419FFFFF 20 (デバッガー ビュー) で、これは 20.00 をバッファーに出力しました。

整数でない場合は、代わりに小数点以下 2 桁を表示したいと思います。

94.74 displayed as 94.74
94.7  displayed as 94.70
0     displayed as 0
5     displayed as 5
100   displayed as 100

現在、次のコードを使用しています。

static void MyFunc(char* buffer, const float percentage)
{
    int fractional_part = ((percentage - (int)percentage) * 100);
    if (0 == fractional_part)
    {
        sprintf(buffer, "%d", (int)percentage);
    }
    else
    {
        sprintf(buffer, "%.2f", percentage);
    }
}

ここで、0x419FFFFF 20 (デバッガー ビュー) が渡されると、小数部は 99 として計算されます。私は、fractional_part の合計が (19.99 - 19) * 100 = 99 になると仮定します。なぜ最初の例で 19.99 がバッファーに出力されないのでしょうか?

私の問題の正しい解決策は何ですか?

4

2 に答える 2

6

あなたのものは近似の問題です。

パーセンテージが 19.999 であるとします。次にfractional_part99 になり、浮動小数点分岐が呼び出されます。

しかし、小数点以下 2 桁で 19.999 を出力すると、20.00 に丸められ、それ出力されます。

一貫した結果を得るために、常に浮動小数点ブランチを使用してから、「.」で切り捨てることができます。「.00」で出てくる場合。そうしないと、テストとprintfの内部がいつか衝突する危険があります。

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
        float percentage = 19.999;
        char buffer[50];

        for (percentage = 19.990; percentage < 20.001; percentage += 0.001)
        {
                sprintf(buffer, "%.2f", percentage);
                char *p = strstr(buffer, ".00");
                if (p) *p = 0x0;
                printf("%.3f rendered as %.2f and becomes %s\n", percentage, percentage, buffer);
        }
        return 0;
}

19.990 rendered as 19.99 and becomes 19.99
19.991 rendered as 19.99 and becomes 19.99
19.992 rendered as 19.99 and becomes 19.99
19.993 rendered as 19.99 and becomes 19.99
19.994 rendered as 19.99 and becomes 19.99
19.995 rendered as 19.99 and becomes 19.99
19.996 rendered as 20.00 and becomes 20
19.997 rendered as 20.00 and becomes 20
19.998 rendered as 20.00 and becomes 20
19.999 rendered as 20.00 and becomes 20
20.000 rendered as 20.00 and becomes 20
20.001 rendered as 20.00 and becomes 20

printfの丸め戦略に同意しない場合はround()、 on (a copy of)を使用してpercentage、独自のものを強制してください。または、たとえばsprintf()3 桁で 3 番目を消去することもできます。

そして、あなたの特定のケースでは (私のシステム (Linux x86_64) が 0x419FFFFF をレンダリングする方法に注意してください):

#include <stdio.h>
#include <string.h>
#include <stdint.h>

int main(int argc, char **argv)
{
        float percentage = 3.1415;
        char buffer[50];

        ((uint32_t *)(&percentage))[0] = 0x419FFFFF;

        sprintf(buffer, "%.2f", percentage);
        char *p = strstr(buffer, ".00");
        if (p) *p = 0x0;
        printf("%.15f rendered as %.2f and becomes %s\n", percentage, percentage, buffer);
        return 0;
}


19.999998092651367 rendered as 20.00 and becomes 20
于 2013-01-24T11:35:07.030 に答える
0

ceilf(f) == f小数部を自分で計算する代わりに、 orが整数の場合floorf(f) == fに返すものを使用することができます。別の代替手段は、標準ライブラリまたは数学から使用することですtruefmodf (float x, float *ipart)fmod

于 2013-01-24T11:27:14.733 に答える