C++ 印刷浮动,保持精度

C++ 印刷浮动,保持精度,c++,c,string,floating-point,floating-accuracy,C++,C,String,Floating Point,Floating Accuracy,我正在编写一个程序,它打印浮点文本以在另一个程序中使用 为了保持原始浮点的精度,我需要打印多少位数 由于浮点数的精度为24*(log(2)/log(10))=7.2247199小数位数,我最初的想法是打印8位数就足够了。但是如果我运气不好,那些0.2247199会分布到7个有效数字的左侧和右侧,因此我可能应该打印9个十进制数字 我的分析正确吗?所有情况下,9位小数是否足够?如printf(“%.9g”,x) 在7或8足够的情况下,是否有一个标准函数可以将浮点转换为具有该值所需的最小小数位数的字符

我正在编写一个程序,它打印浮点文本以在另一个程序中使用

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

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

我的分析正确吗?所有情况下,9位小数是否足够?如
printf(“%.9g”,x)

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


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

< P> java中使用的浮点到十进制转换保证在小数点之外产生最少数量的小数点,以区别数字与邻居(或多或少)。p> 您可以从此处复制算法:
请注意
FloatingDecimal(float)
构造函数和
toJavaFormatString()
方法。

您可以使用
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
*/
#包括
内部主(空)
{
浮点数d_n=123.45;
char s_cp[13]={'\0'};
char s_cnp[4]={'\0'};
/*
*使用sprintf,您需要确保有足够的空间
*在数组中声明
*/
sprintf(s_cp,.2f%,d_n);
printf(“%s\n”,s\u cp);
/*
*snprinft允许控制数组中的读取量。
*如果您不使用C99,它可能会有可移植性问题
*/
snprintf(s_cnp,s_cnp的大小-1,“%f”,d_n);
printf(“%s\n”,s_cnp);
getchar();
返回0;
}
/*输出:
* 123.45
* 123
*/
24*(对数(2)/对数(10))=7.2247199

这很能代表这个问题。以0.0000001位数的精度表示有效位数是毫无意义的。您将数字转换为文本是为了人类的利益,而不是机器的利益。如果你写信的话,人类会毫不在乎,而且更愿意

24*(日志(2)/日志(10))=7

尝试显示8个有效数字只会生成随机噪声数字。由于浮点误差在计算中累积,7已经太多的可能性为非零。最重要的是,使用合理的计量单位打印数字。人们对毫米、克、磅、英寸等感兴趣。没有一个建筑师会关心窗户的尺寸是否比1毫米更精确。没有一家窗户制造厂能保证窗户尺寸如此精确

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

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;
}

但是请注意,并不是所有的值都可以用这种方式表示,这只是一个简单的例子,应该可以给出想法,但可能需要改进。

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

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

解码只是颠倒过程(在大多数平台上,可以使用直接的
重新解释。

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

在C中,可以用于这些转换的函数是snprintf()和strof/strod/strtold()


当然,在某些情况下,甚至更多的数字可能是有用的(不,它们并不总是“噪声”,这取决于十进制转换例程(如snprintf())的实现)。例如,如果你有一个符合C99的C库(如果你的浮点类型有一个基数是2的幂):<代码> Prtff <代码>格式化字符>代码> %A<代码>可以打印浮点值,而十六进制的形式没有精度,如果你阅读这些论文(见下文),你会发现有一些算法可以打印小数位数的最小值,这样数字就可以在不改变的情况下重新解释(即通过scanf)

由于可能存在多个这样的数字,该算法还选择与原始二进制分数(我称为浮点值)最接近的十进制分数

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


使用1000位数字并剪裁尾随的零!;)由于无法将基于二进制的浮点转换为十进制分数,因此我建议只转储二进制表示法(或尾数+指数)?不是所有的二进制分数都可以表示为有限十进制吗?@Fred:不会,但至少这种表示是准确的,所以你可以在其他程序中提取它,并从中生成完全相同的浮点值。@FredOverflow:你能澄清一下目的吗?是为了得到浮点的精确十进制表示吗?(如果是这样的话,R.Martinho就在正确的轨道上了。)还是要打印到足够的精度,以使其能够明确无误

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.