我正在编写一个打印浮点文字的程序,以便在另一个程序中使用。
为了保持原始浮动的精度,我需要打印多少位?
由于浮点数的精度为十进制数24 * (log(2) / log(10)) = 7.2247199
,我最初的想法是打印8位数就足够了。但如果我运气不好,那些0.2247199
会分配到7位有效数字的左侧和右侧,所以我应该打印9位小数。
我的分析是否正确?所有情况下都是9位十进制数字吗?喜欢printf("%.9g", x);
?
是否有标准函数将float转换为具有该值所需的最小小数位数的字符串,在7或8足够的情况下,所以我不打印不必要的数字?
注意:我不能使用十六进制浮点文字,因为标准C ++不支持它们。
答案 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
可以打印浮点值而不用十六进制形式缺乏精确度,scanf
和strod
实用程序将能够读取它们。
答案 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;
}
但请注意,仍然不是所有的价值都可以用这种方式来表示,它只是一个应该给出这个想法的快速镜头,但可能需要改进。