C++:如何将浮点数转换为字符串而不进行四舍五入、截断或填充?

7
我遇到了一个问题,无法解决它。需要大师们的帮助。这是示例代码:-
float f=0.01f;
printf("%f",f);

如果我们在调试过程中检查变量的值,发现变量f包含'0.0099999998'的值,而printf输出的是0.010000。

a. 是否有办法强制编译器将相同的值分配给float类型的变量?

b. 我想将float转换为字符串/字符数组。是否可能仅将完全相同的值转换为字符串/字符数组?我想确保没有填充零、填充不需要的值或更改数字,如上例所示。

10个回答

6

使用二进制值表示十进制数是不准确的,除了一些特定的数值(如0.25)。如果需要精确表示,必须从float/double内置类型转换为某种十进制数包。


3
您可以这样使用boost::lexical_cast
float blah = 0.01;
string w = boost::lexical_cast<string>( blah );

变量w将包含文本值0.00999999978。但我看不出你什么时候真正需要它。

最好使用boost::format来准确地将浮点数格式化为字符串。以下代码展示了如何实现:

float blah = 0.01;
string w = str( boost::format("%d") % blah ); // w contains exactly "0.01" now

2

请查看这个 C++ 参考文献,特别是精度部分:

float blah = 0.01;
printf ("%.2f\n", blah);

我认为他遇到了浮点数而不是双精度问题。 - Aamir
呵呵...这很酷。我想最初的负评可能是因为我的第一个非常简短的回答(没有源代码),这也是公平的;)。 - RedBlueThing
可能也是因为我忽略了浮点数表示问题,只是在表面上回答了这个问题。 - RedBlueThing

2

存在无数个实数。

floatdoublelong double这些数据类型只能取有限数量的值。

也就是说,有无数个实数无法用这些数据类型精确表示。


1

你的调试器给出不同值的原因在Mark Ransom的帖子中有很好的解释。

关于打印浮点数而不进行四舍五入、截断并具有更完整的精度,你缺少了精度说明符 - printf的默认精度通常为6个小数位。

尝试以下代码以获得10位精度:

float amount = 0.0099999998;
printf("%.10f", amount); 

作为一个旁注,更符合C++风格(而非C风格)的做法是使用cout:
float amount = 0.0099999998;
cout.precision(10);
cout << amount << endl;

1
对于(b),你可以这样做:
std::ostringstream os;
os << f;
std::string s = os.str();

1
同样地,您可以使用stdlib.h,在其中有sprintf、ecvt和fcvt函数(或者至少应该有)。
int sprintf(char* dst,const char* fmt,...);

char *ecvt(double value, int ndig, int *dec, int *sign);

char *fcvt(double value, int ndig, int *dec, int *sign);

sprintf 返回它写入字符串的字符数,例如

float f=12.00;
char buffer[32];
sprintf(buffer,"%4.2f",f) // will return 5, if it is an error it will return -1

ecvtfcvt将字符返回到包含数字的静态char*位置,没有小数点,最重要的数字在前面,小数点的偏移量存储在dec中,符号在“sign”中(1=-,0=+),ndig是要存储的有效数字的数量。如果dec<0,则必须在小数点之前用-dec个零进行填充。如果您不确定,并且您不是在Windows7系统上工作(有时无法运行旧的DOS3程序),请查找Dos 3的TurboC版本2,仍然有一两个可用的下载,这是Borland的一个相对较小的Dos C / C ++编辑器/编译器,甚至带有TASM,16位机器代码386/486编译器,它在帮助文件中涵盖,以及许多其他有用的信息。

所有三个例程都在“stdlib.h”中,或者应该在其中,尽管我发现在VisualStudio2010上它们与标准完全不同,经常重载处理WORD大小的字符的函数,并要求您使用其自己的特定函数...“标准库太多了”,我几乎每次都会自言自语,“也许他们应该得到一个更好的字典!”


1
实际上,使用浮点处理器、协处理器或芯片本身的部分(现在大多数都集成到CPU中)将永远不会产生准确的数学结果,但它们可以提供相当粗略的准确度。对于更准确的结果,您可以考虑定义一个名为“DecimalString”的类,该类使用nybbles作为十进制字符和符号,并尝试使用字符串模拟基于10的数学运算。在这种情况下,取决于您想要使字符串有多长,您甚至可以完全放弃指数部分,一个字符串256可以表示1x10^-254到1^+255的直接十进制,使用实际ASCII,如果您想要一个符号,则更短,但这可能会明显变慢。您可以通过反转数字顺序来加快速度,因此从左到右读取单位、十位、百位、千位等。 简单示例 例如,“0021”变成1200 在进行例程之前,需要将其向左和向右“移位”以使小数点对齐,最好的方法是从ADD和SUB函数开始,因为然后您将在MUL和DIV函数中构建它们。如果您在一台大型机器上,理论上可以使它们的长度与您的心愿一样长!

0

您需要查阅平台标准以确定如何最好地确定正确的格式,您需要将其显示为a*b^C,其中'a'是保留符号的整数部分,'b'是实现定义(可能由标准固定),而'C'是用于该数字的指数。

或者,您可以将其显示为十六进制,但对人类来说毫无意义,并且在所有实际目的上仍然是二进制。(并且同样可移植!)


0
回答你的第二个问题:
可以将浮点数精确无歧义地表示为字符串。但是,这需要使用十六进制表示法。例如,1/16 = 0.1,10/16 是 0.A。
使用十六进制浮点数,您可以定义一个规范化的表示法。我个人会使用表示基础位数的固定位数的数字,但您也可以决定去掉尾随零。没有混淆可能会出现在哪些尾随数字是零。
由于表示是精确的,所以转换是可逆的:f==hexstring2float(float2hexstring(f))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接