印花浮子,保持精度

时间:2012-06-05 10:00:29

标签: c++ c string floating-point floating-accuracy

我正在编写一个打印浮点文字的程序,以便在另一个程序中使用。

为了保持原始浮动的精度,我需要打印多少位?

由于浮点数的精度为十进制数24 * (log(2) / log(10)) = 7.2247199,我最初的想法是打印8位数就足够了。但如果我运气不好,那些0.2247199会分配到7位有效数字的左侧和右侧,所以我应该打印9位小数。

我的分析是否正确?所有情况下都是9位十进制数字吗?喜欢printf("%.9g", x);

是否有标准函数将float转换为具有该值所需的最小小数位数的字符串,在7或8足够的情况下,所以我不打印不必要的数字?

注意:我不能使用十六进制浮点文字,因为标准C ++不支持它们。

8 个答案:

答案 0 :(得分:16)

为了保证二进制 - >十进制 - >二进制往返恢复原始二进制值,IEEE 754需要


The original binary value will be preserved by converting to decimal and back again using:[10]

    5 decimal digits for binary16
    9 decimal digits for binary32
    17 decimal digits for binary64
    36 decimal digits for binary128

For other binary formats the required number of decimal digits is

    1 + ceiling(p*log10(2)) 

where p is the number of significant bits in the binary format, e.g. 24 bits for binary32.

在C中,您可以用于这些转换的函数是snprintf()和strtof / strtod / strtold()。

当然,在某些情况下甚至更多的数字可能是有用的(不,它们并不总是“噪声”,这取决于十进制转换例程的实现,例如snprintf())。考虑例如printing dyadic fractions

答案 1 :(得分:3)

  

24 *(log(2)/ log(10))= 7.2247199

这个问题很有代表性。没有任何意义表达有效位数,精度为0.0000001位。您正在将数字转换为文本,以使 human 受益,而不是机器。如果你写了

,一个人可能不会在意,也会更喜欢
  

24 *(log(2)/ log(10))= 7

尝试显示8位有效数字只会生成随机噪声数字。由于浮点误差在计算中累积,因此非零赔率7已经过多。最重要的是,使用合理的度量单位打印数字。人们对毫米,克,磅,英寸等感兴趣。没有建筑师会关心窗口的尺寸比1毫米更准确。没有窗户制造工厂会承诺一个像那样精确的窗户。

最后但同样重要的是,您无法忽略您输入程序的数字的准确性。将空载欧洲燕子的速度测量到7位数是不可能的。它大约是每秒11米,最多2位数。因此,对该速度执行计算并打印具有 more 有效数字的结果会产生无意义的结果,从而保证不存在的精确度。

答案 2 :(得分:2)

如果程序是由计算机读取的,我会使用char*别名的简单技巧。

  • 别名float*char*
  • 通过unsigned别名
  • 复制到char*(或任何无符号类型足够大)
  • 打印unsigned

解码只是改变了流程(在大多数平台上,可以使用直接reinterpret_cast)。

答案 3 :(得分:2)

如果你有一个符合C99的C库(如果你的浮点类型的基数是2的幂:),printf格式字符%a可以打印浮点值而不用十六进制形式缺乏精确度,scanfstrod实用程序将能够读取它们。

答案 4 :(得分:1)

Java中使用的浮点到十进制转换保证产生超出小数点的最小十进制数,以区分数字与其邻居(或多或少)。

您可以从此处复制算法:http://www.docjar.com/html/api/sun/misc/FloatingDecimal.java.html 请注意FloatingDecimal(float)构造函数和toJavaFormatString()方法。

答案 5 :(得分:1)

如果您阅读这些论文(见下文),您会发现有一些算法可以打印最小的十进制数字,以便可以不加改变地重新解释该数字(即通过scanf)。

由于可能有几个这样的数字,算法也会选择最接近原始二进制分数的小数部分(我命名为浮点值)。

遗憾的是,C中没有这样的标准库。

答案 6 :(得分:0)

您可以使用sprintf。我不确定这是否完全回答了你的问题,但无论如何,这里是示例代码

#include <stdio.h>
int main( void )
{
float d_n = 123.45;
char s_cp[13] = { '\0' };
char s_cnp[4] = { '\0' };
/*
* with sprintf you need to make sure there's enough space
* declared in the array
*/
sprintf( s_cp, "%.2f", d_n );
printf( "%s\n", s_cp );
/*
* snprinft allows to control how much is read into array.
* it might have portable issues if you are not using C99
*/
snprintf( s_cnp, sizeof s_cnp - 1 , "%f", d_n );
printf( "%s\n", s_cnp );
getchar();
return 0;
}
/* output :
* 123.45
* 123
*/

答案 7 :(得分:-1)

类似

def f(a):
    b=0
    while a != int(a): a*=2; b+=1
    return a, b

(这是Python)你应该能够以无损方式获得尾数和指数。

在C中,这可能是

struct float_decomp {
    float mantissa;
    int exponent;
}

struct float_decomp decomp(float x)
{
    struct float_decomp ret = { .mantissa = x, .exponent = 0};
    while x != floor(x) {
        ret.mantissa *= 2;
        ret.exponent += 1;
    }
    return ret;
}

但请注意,仍然不是所有的价值都可以用这种方式来表示,它只是一个应该给出这个想法的快速镜头,但可能需要改进。