2

我有一个代码示例:

float f = 3.55f;
printf("%.1f\n", f);

结果是 3.5,而不是所需的 3.6。

float delta = 1e-7;
float f = 3.55f;
printf("%.1f\n", f+delta);

现在结果是 3.6,但是当 f 是 0.0499999f 时;

printf("%.1f\n", f+delta);

结果结果是 0.1,而不是 0.0。

我需要一个将 3.55 转换为 3.6、0.0499999 转换为 0.0 的函数,有人能提供线索吗?

4

6 回答 6

2

与许多浮点问题一样,问题在于您的值并不是真正的 3.55

float f = 3.55f;
printf("%.10f\n", f);  // 3.5499999523

另见http://floating-point-gui.de/

所以除非你使用ceil(),否则这个值永远不会被四舍五入。

于 2013-06-08T14:56:15.013 回答
0

其他人指出,示例中的十进制值没有精确的二进制等价物。

然后是增量:

  1. 有一个小数增量可能会弄乱你的四舍五入,因为将一个无法表示的数字添加到另一个数字并不是最优的。
  2. 增量应基于二进制值,其数量级为 1/(2^23) 的 2^ 所显示数字的指数(单精度)或 1/(2^52)(双精度)。

对于 16 <= x < 32 (exponent = 4) 范围内的单精度数 x,增量应为 2^(4-23) 或 2^-19。

于 2013-06-08T21:30:24.830 回答
0

H2CO3 对相关问题的答案的修改产生了所需的输出:

float custom_round(float num, int prec)
{
    float trunc = round(num * pow(10, prec+7));
    trunc = round(trunc/pow(10, 7));
    return trunc / pow(10, prec);
}

额外的7精度来自该delta值。我不认为它普遍适用,但是对于两个数字3.55f0.0499999f,它指向的位置是第一个数字将向上舍入,而第二个数字将向下舍入。

于 2013-06-08T15:37:47.993 回答
0

问:...函数将 3.55 转换为 3.6,将 0.0499999 转换为 0.0 ...?
答:使用@Kninnug 答案,但保留小数点后一位。

f = round(f * 10) / 10.0;

它会给你,因为3.5这个数字最初f不是3.55。没错,您使用文本“3.55”进行了初始化,但您的计算机无法准确表示该数字。 您的系统上没有 (float) 3.55。相反,它的价值约为,因为它是最接近的选择。fCf3.549999952...

如果您希望显示f舍入为 3.6 而不是 3.5,则需要f稍微提高一点。轻推什么时候它3.549999952...的值 >= 3.55,什么时候f0.04999990016...(0.0499999 也不能完全表示)相同的轻推使它保持f< 0.5。

f我们可以增加并看到变化的最小的是nextafterf(f, g). g是您希望达到的值。

3.549999952...   --> 3.550000190...
0.04999990016... --> 0.04999990389...

printf("%.1f\n", nextafterf(f, 2*f));
// prints 3.6 when f is 3.549999952...
// prints 0.0 when f is 0.04999990389...

建议您查看@Oli Charlesworth 答案中的参考资料。

于 2013-06-09T23:36:04.390 回答
-1

在这里,这段代码有效。我对代码进行了注释,以便您理解它。

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

int main(int argc, char const *argv[])
{
    float delta = 1e-7;
    float f = 3.55f;

    // Here we minus f (3.55) from the integer of f (3) so 3.55 - 3 = 0.55
    // Then we check whether the value is bigger than 0.5
    if( (f-(int)f) >= 0.5 ) { 
            // If it is, then plus 0.01 to the answer. Thus making it 3.65
        f = f + 0.01;
    } else {
            // If its not, minus 0.01 from the answer.
            // Assuming f is 3.44 this will make f 3.43
        f = f - 0.01;
    }

    // Since you its to the first decimal place, the code above will output 
    // your desired result which is 3.6.
    printf("%.1f\n", f+delta);
    return 0;
}
于 2013-06-08T15:09:00.850 回答
-1

我希望这能帮到您。这是一个完整的程序,但您只能使用该功能。

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

//function prototypes
float roundon(float n,int to);

void main(){
    //vars
    float num;
    int roundto;
    puts("Enter the decimal to be rounded");
    scanf("%f",&num);

    puts("Enter the number of decimal places to be rounded");
    scanf("%d",&roundto);

    float rounded= roundon(num,roundto);
    printf("The rounded value is %f\n",rounded);
}

//functions
float roundon(float n, int to){
    //vars
    float rounded;

    int checker=(int) (n*pow(10,(to+1)))%10;
    int dec= (int) (n*pow(10,to));
    if(checker>=5){
        dec++;
    }

    rounded= (float) dec/(pow(10,to));
    return (rounded);
}
于 2013-06-08T16:24:52.637 回答