如何在不丢失用户在 C 中输入的精度的情况下将浮点数转换为字符串?
How to convert float number to string without losing user-entered precision in C?
这是我正在尝试做的事情:
- 我需要打印一个浮点数的小数部分,它必须在用户输入时作为 float 输入。
- 小数部分应该是这样的:如果float是43.3423,输出应该是3423;如果数字是 45.3400 输出应该是 3400.
- 这可以通过字符串输入轻松完成,但我需要一种方法来使它与
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: 950000 <= x < 1050000
。
浮点数使用相同的格式,但使用二进制数字(有时称为位 ;))而不是十进制数字。但有两个重要区别:
- 使用的位数(位数)仅取决于浮点数的数据类型。如果您的数据类型有例如20位为尾数,每一个存入的数都会有这20位。尾数总是在 "decimal"(二进制?)点之后没有部分存储,因此您将不知道有多少 significant 位。
- 位和十进制数字之间没有直接映射。您将需要 大约 3.5 位来表示十进制数字。所以 即使你知道 一些 重要的 位,你仍然不知道有多少 重要的小数位 那会让。
为了解决您的问题,您可以自己存储有效数字的数量,如下所示:
struct myNumber
{
double value;
int nsignificant;
};
当然,您必须自己解析 输入以找出要放在nsignificant
中的内容。另外,这里至少使用 double
作为值,float
的非常有限的精度不会让你走得太远。有了这个,您可以使用 nsignificant
来确定一个正确的格式字符串,用于打印带有您想要的位数的数字。
这仍然存在上述问题:您不能直接将十进制数字映射到位,因此永远无法保证您的数字可以按照您想要的精度存储。在精确的十进制表示很重要的情况下,您需要为此使用不同的数据类型。 C# provides one,但 C 没有。你必须自己实施它。你可以从这样的事情开始:
struct myDecimal
{
long mantissa;
short exponent;
short nsignificant;
}
在此结构中,您可以例如像这样放置 1.0e6
:
struct myDecimal x = {
.mantissa = 1;
.exponent = 6;
.nsignificant = 2;
};
当然,这需要您自己编写大量代码来解析和格式化这些数字。
唯一的方法是使用原始字符串值和/或舍入所需的精度创建结构
which has to be input as a float during user input.
So, is there a way to get this done.
差不多。 “技巧”是注意用户输入的文本长度。下面会记住第一个非空白字符的偏移量和数字输入后的偏移量。
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;
}
Input/Output
43.3423
<3423>
45.3400
<3400>
-45.3400
<3400>
0.00
<00>
1234.500000
<500000>
.
.
为了稳健地处理这种情况和各种边缘情况,代码应该将用户输入读取为 text 而不是 float
.
注意:float
通常可以表示大约 232 个数字 正好.
43.3423
通常不是其中之一。相反,它的准确值为 43.3423004150390625
43.3400
通常不是其中之一。相反,它的准确值为 43.340000152587890625
这是我正在尝试做的事情:
- 我需要打印一个浮点数的小数部分,它必须在用户输入时作为 float 输入。
- 小数部分应该是这样的:如果float是43.3423,输出应该是3423;如果数字是 45.3400 输出应该是 3400.
- 这可以通过字符串输入轻松完成,但我需要一种方法来使它与
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: 950000 <= x < 1050000
。
浮点数使用相同的格式,但使用二进制数字(有时称为位 ;))而不是十进制数字。但有两个重要区别:
- 使用的位数(位数)仅取决于浮点数的数据类型。如果您的数据类型有例如20位为尾数,每一个存入的数都会有这20位。尾数总是在 "decimal"(二进制?)点之后没有部分存储,因此您将不知道有多少 significant 位。
- 位和十进制数字之间没有直接映射。您将需要 大约 3.5 位来表示十进制数字。所以 即使你知道 一些 重要的 位,你仍然不知道有多少 重要的小数位 那会让。
为了解决您的问题,您可以自己存储有效数字的数量,如下所示:
struct myNumber
{
double value;
int nsignificant;
};
当然,您必须自己解析 输入以找出要放在nsignificant
中的内容。另外,这里至少使用 double
作为值,float
的非常有限的精度不会让你走得太远。有了这个,您可以使用 nsignificant
来确定一个正确的格式字符串,用于打印带有您想要的位数的数字。
这仍然存在上述问题:您不能直接将十进制数字映射到位,因此永远无法保证您的数字可以按照您想要的精度存储。在精确的十进制表示很重要的情况下,您需要为此使用不同的数据类型。 C# provides one,但 C 没有。你必须自己实施它。你可以从这样的事情开始:
struct myDecimal
{
long mantissa;
short exponent;
short nsignificant;
}
在此结构中,您可以例如像这样放置 1.0e6
:
struct myDecimal x = {
.mantissa = 1;
.exponent = 6;
.nsignificant = 2;
};
当然,这需要您自己编写大量代码来解析和格式化这些数字。
唯一的方法是使用原始字符串值和/或舍入所需的精度创建结构
which has to be input as a float during user input.
So, is there a way to get this done.
差不多。 “技巧”是注意用户输入的文本长度。下面会记住第一个非空白字符的偏移量和数字输入后的偏移量。
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;
}
Input/Output
43.3423
<3423>
45.3400
<3400>
-45.3400
<3400>
0.00
<00>
1234.500000
<500000>
.
.
为了稳健地处理这种情况和各种边缘情况,代码应该将用户输入读取为 text 而不是 float
.
注意:float
通常可以表示大约 232 个数字 正好.
43.3423
通常不是其中之一。相反,它的准确值为 43.3423004150390625
43.3400
通常不是其中之一。相反,它的准确值为 43.340000152587890625