[英]How to convert float number to string without losing user-entered precision in C?
这是我想做的事情:
float
进行此工作的方法,而不会丢失额外的零或无需在用户的原始输入中附加零。 frac = num - (int)num
,然后乘以frac
直到得到零。 但这在34.3400之类的情况下失败了-该方法不会包含最后两个零。 将浮点数转换为字符串
char string[20]; sprintf(string, "%f", float_number);
sprintf
函数将浮点数作为字符串放置,但在这里它也不会自动检测用户输入的精度,并在字符串末尾添加额外的零(6个总精度)。 因此,这里也没有获得有关用户原始输入精度的信息。
那么,有没有办法做到这一点? 该数字必须作为用户的浮动数字。 有没有办法获取有关用户输入的精度的信息? 如果不可能,那么进行解释将非常有帮助。
我想我知道你来自哪里。 例如,在物理学中,无论您写42.5
还是42.500
不同, 有效位数是隐式给出的。 42.5
代表任意数字x: 42.45 <= x < 42.55
和42.500
代表任意x: 42.4995 <= x < 42.5005
。
对于较大的数字,应使用科学计数法 : 1.0e6
表示x等于x的数字x: 950000 <= x < 1050000
。
浮点数使用相同的格式,但使用二进制数字(有时称为位;)代替十进制数字。 但是有两个重要的区别:
为了解决您的问题,您可以将自己的有效数字存储在类似以下的内容中:
struct myNumber
{
double value;
int nsignificant;
};
当然,您必须自己解析输入以找出要放在nsignificant
。 另外, 在此处至少使用double
作为该值, float
的非常有限的精度不会使您走得太远。 这样,您可以使用nsignificant
来确定适当的格式字符串,以打印带有所需位数的数字。
这仍然存在上面提到的问题:您不能直接将十进制数字映射到位,因此永远不能保证您的数字可以以您想要的精度存储。 如果精确的十进制表示很重要,则需要使用其他数据类型。 C#提供了一个 ,但C没有提供。 您必须自己实施。 您可以从以下内容开始:
struct myDecimal
{
long mantissa;
short exponent;
short nsignificant;
}
在这个结构中,您可以像这样放置1.0e6
:
struct myDecimal x = {
.mantissa = 1;
.exponent = 6;
.nsignificant = 2;
};
当然,这将需要您编写很多自己的代码来解析和格式化这些数字。
唯一的方法是使用原始字符串值和/或舍入所需的精度来创建结构
在用户输入期间必须将其作为浮点输入。
因此,有没有一种方法可以做到这一点。
几乎。 “技巧”是要注意用户输入的文本长度。 下面将记住第一个非空白字符的偏移量和数字输入后的偏移量。
scanf(" %n%f%n", &n1, &input, &n2);
n2 - n1
给出代码,以用户输入的长度表示float
。 如果用户输入采用指数表示法,十六进制FP表示法,无穷大,非数字,过多的前导零等,则此方法可能会被愚弄。但是,对于直接十进制输入,该方法很好。
想法是将数字打印到精度至少为n2 - n1
的缓冲区中,然后确定要打印的小数部分。
回想一下, float
通常具有大约6-7个重要的有效前导位数,因此,尝试输入“ 123456789.0”之类的文本将导致float
的确切值为123456792.0
,并且输出将基于该值。
#include <float.h>
#include <math.h>
int scan_print_float(void) {
float input;
int n1, n2;
int cnt = scanf(" %n%f%n", &n1, &input, &n2);
if (cnt == 1) {
int len = n2 - n1;
char buf[len * 2 + 1];
snprintf(buf, sizeof buf, "%.*f", len, input);
char dp = '.';
char *p = strchr(buf, dp);
if (p) {
int front_to_dp = p + 1 - buf;
int prec = len - front_to_dp;
if (prec >= 0) {
return printf("<%.*s>\n", prec, p+1);
}
}
}
puts(".");
return 0;
}
int main(void) {
while (scan_print_float()) {
fflush(stdout);
}
return EXIT_SUCCESS;
}
输入输出
43.3423
<3423>
45.3400
<3400>
-45.3400
<3400>
0.00
<00>
1234.500000
<500000>
.
.
为了稳健地处理这种情况和各种边缘情况,代码应将用户输入作为文本而不是float
读取。
注意: float
通常可以精确表示约2 32个数字。
43.3423
通常不是其中之一。 取而代之的是它的确切值为43.3423004150390625
43.3400
通常不是其中之一。 取而代之的是它的精确值是43.340000152587890625
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.