关注这个问题:
这是我的尝试:
#include <stdio.h>
#include <math.h>
void dbl2str(char *s, double number, int decimals)
{
double integral, fractional;
int n, i;
fractional = modf(number, &integral);
n = sprintf(s, "%d%c", (int)integral, decimals ? '.' : 0);
for (i = 0; i < decimals; i++) {
fractional *= 10;
s[n + i] = '0' + (int)fractional;
fractional = modf(fractional, &integral);
}
s[n + i] = '\0';
}
int main(void)
{
char s[32];
dbl2str(s, 3.1416, 4);
printf("%s\n", s);
dbl2str(s, 3.159, 4);
printf("%s\n", s);
dbl2str(s, 3.04, 2);
printf("%s\n", s);
return 0;
}
输出:
3.1415
3.1589
3.04
正如您所看到的有圆形错误,有没有办法获得正确的输出?
答案 0 :(得分:1)
问题在于,0.0006并不能完全代表二进制,而是表示将完全匹配0.0005999 ......这意味着当你将乘法乘以10四次时,你得到5作为你的最后一位而不是10.您需要查看序列中的下一个数字并进行适当的舍入(在这种情况下,下一个数字将大于5)。
小心舍入,因为向上舍入最后一个数字可能会导致前一个数字向上舍入(如果最后一个数字也是9)。
答案 1 :(得分:1)
该行
s[n + i] = '0' + (int)fractional;
将fractional
部分截断为整数。您希望最后一位数字正确舍入,因此您必须将其视为与其他数字不同:
void dbl2str(char *s, double number, int decimals)
{
double integral, fractional;
int n, i;
fractional = modf(number, &integral);
if (fractional < 0)
fractional = -fractional;
n = sprintf(s, "%d%c", (int)integral, decimals ? '.' : 0);
for (i = 0; i < decimals-1; i++) {
fractional *= 10;
s[n++] = '0' + (int)fractional;
fractional = modf(fractional, &integral);
}
fractional *= 10;
s[n++] = '0' + (int)(fractional+0.5f);
fractional = modf(fractional, &integral);
s[n] = '\0';
}
我也为负数添加了测试。没有,fractional
部分就会疯狂。
答案 2 :(得分:0)
添加:
if(i == decimals - 1)
fractional = round(fractional);
在fractional *= 10;
之后
答案 3 :(得分:0)
我会做像
这样的事情void dbl2str(char *s, double number, int decimals)
{
double integral, fractional;
int n, i;
/* use an epsilon and add the correct rounding value */
double eps= 1e-9;
double round = 0.5*pow(10,-decimals);
fractional = modf(number+round+eps, &integral);
n = sprintf(s, "%d%c", (int)integral, decimals ? '.' : 0);
for (i = 0; i < decimals; i++) {
fractional *= 10;
s[n + i] = '0' + (int)fractional;
fractional = modf(fractional, &integral);
}
s[n + i] = '\0';
}
这样,我添加0.5 * 10 ^ -decimals以使(int) fractional
正确舍入到epsilon。
适用于您的输入:
3.1416
3.1590
3.04
当然,您可能需要根据数字调整epsilon,然后考虑您已经用尽16位精度的情况。总的来说,这很难做到。