c - 从 C 中的 float 转换整数的不一致舍入

标签 c casting floating-point precision

我一整天都在为这个小问题而焦头烂额,事实证明我很难解决这个问题,而且我相当确定在表面之下发生了一些我不知道的事情。非常欢迎任何反馈或帮助。

我有一个函数,它接受一个浮点值并返回一串 ASCII 字符以输出到 LCD 屏幕上。因此函数是:

char returnString(float x, bool isTriggTemp)
{
    char numberString[3];
    char bufferString[2];
    char bufferStringDec[7];

    int integerVal = (int)x;

    if(isTriggTemp == false)
    {
        int decimalVal = (x-integerVal)*10000;
        sprintf(numberString, "%s.%s", itoa(bufferString,integerVal,10),
             itoa(bufferStringDec,decimalVal,10));
    }
    else
    {
        int decimalVal = (x-integerVal)*1000; 

        sprintf(numberString, "%s.%s", itoa(bufferString,integerVal,10),
             itoa(bufferStringDec,decimalVal,10));
    }

    return numberString;
}

If 语句和 bool 的原因是有两个 float 可以传递给函数。一种是小数点后 1 位,另一种是最多 5 位小数。我不会对小数点后 5 位的数字大惊小怪,因为我稍后会在程序中比较这两个 float ,相关的小数点似乎大致一致。

我的查询源于这一行:

 int decimalVal = (x-integerVal)*10;

当像这样使用时,这是我希望在给定上述逻辑的情况下必须使用的,无论 X 值如何,输出的字符串都显示为“X.0”。

将其增加到 100:

 int decimalVal = (x-integerVal)*100;

仅给出偶数的正确值。 (当 float 为 X.2 时,X.2 很好),但对于奇数,我似乎得到了一个四舍五入的版本(X.3 float 打印 X.2、X.5 -> X.4)等。

当我将它增加到 1000 时,我开始看到问题的开始:

int decimalVal = (x-integerVal)*1000;

对于偶数值,例如 X.4,我打印 X.40。对于奇数,我得到的值比原来的 float 少 0.01。例如。 X.5 -> X.49。

显然这里有些不对劲,不精确的小数点被截掉了。 A)我该如何解决这个问题?和 B) 根据算术,我猜应该使用 *10,但 *100 是 10 的阶数,它使我最接近正确的输出。

非常感谢任何帮助。

最佳答案

你可以用 %f 写出你想要的 float 精度。甚至动态地执行精度级别:

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

// Use malloc (drawback: need to track return and deallocate to prevent memory leak.)
char * returnString( float x, int isTriggTemp )
{
    char * buffer = malloc( 128 );
    if( buffer )
        sprintf( buffer, "%0.*f", isTriggTemp ? 4 : 5, x );
    return buffer;
}

// Use static buffer (drawback: non-reentrant)
char * returnStringStatic( float x, int isTriggTemp )
{
    static char buffer[128];
    sprintf( buffer, "%0.*f", isTriggTemp ? 4 : 5, x );
    return buffer;
}

// Use given buffer (drawback: caller needs to be aware of buffer size needs and additional parameters are involved)
char * returnStringGivenBuffer( char * buffer, float x, int isTriggTemp )
{
    sprintf( buffer, "%0.*f", isTriggTemp ? 4 : 5, x );
    return buffer;
}

int main( int argc, char ** argv )
{
    float val = 3.14159;
    int highprecision = 0;

    printf( "Using sprintf\n" );
    printf( "%0.1f\n", val );
    printf( "%0.5f\n", val );
    printf( "%0.*f\n", ( highprecision ? 5 : 1 ), val );
    highprecision = 1;
    printf( "%0.*f\n", ( highprecision ? 5 : 1 ), val );

    printf( "\nUsing sprintf\n" );
    char buffer[128];
    sprintf( buffer, "%0.1f", val );
    printf( "%s\n", buffer );
    sprintf( buffer, "%0.5f", val );
    printf( "%s\n", buffer );
    sprintf( buffer, "%0.*f", ( highprecision ? 5 : 1 ), val );
    printf( "%s\n", buffer );
    highprecision = 1;
    sprintf( buffer, "%0.*f", ( highprecision ? 5 : 1 ), val );
    printf( "%s\n", buffer );

    printf( "\nUsing dynamic allocation\n" );
    char * fval = returnString( val, 0 );
    printf( "%s\n", fval ? fval : "" );
    if( fval ) free( fval );
    fval = returnString( val, 1 );
    printf( "%s\n", fval ? fval : "" );
    if( fval ) free( fval );

    printf( "\nUsing static buffer\n" );
    char * ptr = returnStringStatic( val, 0 );
    printf( "%s\n", ptr );
    ptr = returnStringStatic( val, 1 );
    printf( "%s\n", ptr );

    printf( "\nUsing given buffer\n" );
    ptr = returnStringGivenBuffer( buffer, val, 0 );
    printf( "%s\n", ptr );
    ptr = returnStringGivenBuffer( buffer, val, 1 );
    printf( "%s\n", ptr );

    return 0;
}

结果:

Using sprintf
3.1
3.14159
3.1
3.14159

Using sprintf
3.1
3.14159
3.14159
3.14159

Using dynamic allocation
3.14159
3.1416

Using static buffer
3.14159
3.1416

Using given buffer
3.14159
3.1416

关于c - 从 C 中的 float 转换整数的不一致舍入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34884154/

相关文章:

c - 接收 SIGTERM

arrays - F#类型转换字符串数组

c# 缩小转换不会产生异常

c - 使用大数时,函数 pow() 无法正常工作?

java - JAX-WS 2.0 - 从 xsd :double to xsd:decimal 迁移

c - 尝试使用调用 stat 的 ctime 返回值对 c 中的结构数组进行排序

c - malloc 作为堆栈内存分配的替代方案

python - 将 Cython 融合类型转换为 C++ 指针

c - 如何在 C99 中获取带符号的 float 零?

C 链接阶段不生成警告