将浮点数舍入到 N 个小数位

Posted

技术标签:

【中文标题】将浮点数舍入到 N 个小数位【英文标题】:Mathematically round float to N decimal places 【发布时间】:2018-10-07 07:57:35 【问题描述】:

我想将浮点数/双精度数四舍五入到 n 位小数。但不是在印刷中,而是在一般情况下。 例如:用户的输入是:2.3891 3,所以输出应该是 2.389 或者如果用户输入 5.98441 4,输出应该是:5.9844

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

int main () 

float num;
int decimals;

scanf("%f%d", &num, &decimals); //5.2381 2

int res = num; // res = 5

int power = 1;
int i = 0;
for(i = 0; i < decimals; i++)
    power*=10; // 1 * 10 * 10

int num3 = num * power; // num3 = 523
int num2 = num3 % power;//

float a = num2*1.0 / power*1.0;
// float a = 23*1.0/13.0;
printf("%f %d\n", a, power);

a = res + a;

printf("%f", a);

return 0;

作为这里的输出,我得到:2.390000。我不想有这些零,也不想使用固定的 %.2f。我错过了什么?

【问题讨论】:

你所要求的是不可能的。浮点数没有小数位。 @melpomene 准确地说是“二进制浮点数”,因为decimal floating point numbers 确实存在。但你是对的。 您可以使用printf("%g", a);,这将是remove trailing zeroes。 始终使用double(忘记float 存在)。 double roundn(double x, int n) double b = pow(10, n); int c = (x + 0.5) * b; /*mind overflow*/ return c / b; @UlrichEckhardt:唯一比float 更好的是空间要求。 double 更精确,double(通常)更快,double 避免自动转换为 double。每个浮点变量 4 个额外字节不会对您的可执行文件产生影响(当然,除非您需要巨大的数组)。在float x = 42, y; y = x * 2; 中有两种自动转换:首先,在乘法之前,x 被转换为双精度;之后结果被转换为浮点数。 【参考方案1】:

一般来说,这个任务是不可能的,因为 IEEE 754 转换是二进制浮点数或双精度浮点数的表示。所以上面的行scanf("%f%d", &amp;num, &amp;decimals); //5.2381 2 确实将十进制(以 10 为底)数字转换为二进制浮点数,并且这种转换通常不是 exaxt,因为您只有有限的位数。 您可以减少位数(二进制),但这不是在十进制系统中定义的。 打印一个浮点(双)精度数字,由于将二进制转换为十进制浮点计算,存在第二个不精度。

【讨论】:

【参考方案2】:

您在这里做两件事:1) 计算一个数字的四舍五入值,以及 2) 打印该数字。

计算四舍五入的值

你做得很好。请注意,在将 float 隐式转换为 int 时,C 会进行截断,而不是舍入,因此:

float f = 1.9;
int i = f;

i 设置为1,而不是2。在您的情况下,如果您的输入是“1.229 2”,那么您计算的值是 1.22,而不是 1.23。这可能是您想要的,但可能不是。如果您想将 off 舍入而不是 趋近于零,您可能需要更改:

int num3 = num * power;

到:

int num3 = 0.5 + num * power;

打印四舍五入的值

一旦您计算出该值,您就可以打印它。如果您只想打印四舍五入的小数位数,可以使用printf() 的精度字段,如下所示:

printf("%.*f\n", decimals, a);

【讨论】:

实际上,如果只是输出表示需要四舍五入,那么请使用您正确支持的打印技术; printf() 函数将正确舍入。【参考方案3】:

一般来说,这是不可能的。 C 和 C++ 中的浮点数最终以基数、尾数、符号和指数的形式指定。

十进制浮点数以 10 为底。在现代硬件的实践中极为罕见。一些早期的计算硬件(如 1946 年创建的 ENIAC)支持十进制浮点。然而,这样的表示在现代硬件中相当少见。

现代硬件上最常见的浮点表示使用2(即二进制)为基数。二进制浮点不能表示所有小数。尝试使用2 的负幂之和来表示十进制值0.1(如1/21/41/8 等)。你会发现0.1 的表示涉及十进制的无穷级数。原因类似于分数1/3 不能用有限的小数位表示(即0.33333....,其中数字3 永远重复)。

无理值(如sqrt(2.0)pi 等)也不能以任何有限位数的数字基数精确表示。所以不可能设计出一个固定和有限大小的浮点类型来精确地保存这些值。

【讨论】:

十进制在现代硬件中并不是“非常”罕见的。它不存在于常见的个人使用计算机中。例如,IBM 制造用于商业/工业用途的十进制硬件。

以上是关于将浮点数舍入到 N 个小数位的主要内容,如果未能解决你的问题,请参考以下文章

为啥 as_tibble() 将浮点数舍入到最接近的整数?

如何将浮点数打印到 n 位小数,包括尾随 0?

JS实现浮点数精确舍入小数点

如何在不进行任何舍入的情况下将浮点数转换为小数点后 4 位?

将C ++中的浮点数舍入到一个小数位

将浮点数格式化为 n 位小数