将浮点数格式化为具有可选小数点的有限大小的 char 数组
format floating point number to a char array of limited size with optional decimal point
我需要将浮点数打印成固定数量的字符。这用于严格基于文本的数据协议(是的,我知道)。十进制包含在字符数中。忽略空终止符。没有最小填充要求。小数精度可以是 0 到(缓冲区大小 - 2),而实数的最大数量可以是 0 到缓冲区大小。最小值和最大值钳位以防止真正超出范围的数字在这个问题的外部处理。
假设缓冲区大小为 6 并强制执行最小值和最大值(0.0001 和 999999)的示例:
Original
Buffer (6 chars)
Notes
12445.11897784
12445
Only the 5 digts are kept as there is no room for decimal + value
8846.51548
8846.5
4.54631888315
4.5463
7651
7651
0.87457
.87457
0.8746 would also be acceptable
起初我认为带有 %.6G 的 sprintf 似乎可以工作,直到我意识到它没有将小数点作为字符考虑在内。我的理解不完整吗?
我可以使用 C++17 或更低版本中的任何实用程序来完成上述任务。我也愿意考虑将或已经成为高于 c++17 的版本标准的一部分的库。
看起来很简单:
- 如果数字大于 10000
- 正常打印,没有数字
%.0f
- 如果一个数字大于 1000
- 在逗号后打印一位
%.1f
- 如果一个数字大于 100
- 在逗号后打印两位数字
%.2f
- 如果数字大于 10
2.逗号后3位打印
%.3f
- 如果... 1
- ...
%.4f
- 其他
%.5f
- 删除前导零
注意四舍五入!前任。数字 9.999999 小于 10,但它会打印为 10.000。正因为如此:
- 首先将所需的最高精度数字 -
%.5f
- 打印到字符串中。
- 然后计算结果字符串.
中逗号前的数字
- 然后在逗号前的 count 个数字而不是实际数字上进行上述比较“如果数字大于 100”。
- Trim 逗号后所需位数的字符串。
即。在打印后处理字符串中正确舍入的数字,而不是在打印前,这样可以防止在转换为字符串时更改数字的任何舍入。
这是一个 C++ 17 版本:
#include <iostream>
#include <charconv>
std::string to6(float f) {
std::string s;
s.resize(10);
auto ec = std::to_chars(s.data(), s.data() + s.size(), f, std::chars_format::fixed);
s.resize(6);
if (s.back() == '.')
s.resize(5);
return s;
}
int main()
{
std::cout << to6(12445.11897784) << std::endl;
std::cout << to6(8846.51548) << std::endl;
std::cout << to6(4.54631888315) << std::endl;
std::cout << to6(7651) << std::endl;
std::cout << to6(0.87457) << std::endl;
return 0;
}
注意:我没有检查错误,因为
Min and max value clamping to prevent truly out of range numbers are handled externally to this problem.
我需要将浮点数打印成固定数量的字符。这用于严格基于文本的数据协议(是的,我知道)。十进制包含在字符数中。忽略空终止符。没有最小填充要求。小数精度可以是 0 到(缓冲区大小 - 2),而实数的最大数量可以是 0 到缓冲区大小。最小值和最大值钳位以防止真正超出范围的数字在这个问题的外部处理。
假设缓冲区大小为 6 并强制执行最小值和最大值(0.0001 和 999999)的示例:
Original | Buffer (6 chars) | Notes |
---|---|---|
12445.11897784 | 12445 | Only the 5 digts are kept as there is no room for decimal + value |
8846.51548 | 8846.5 | |
4.54631888315 | 4.5463 | |
7651 | 7651 | |
0.87457 | .87457 | 0.8746 would also be acceptable |
起初我认为带有 %.6G 的 sprintf 似乎可以工作,直到我意识到它没有将小数点作为字符考虑在内。我的理解不完整吗?
我可以使用 C++17 或更低版本中的任何实用程序来完成上述任务。我也愿意考虑将或已经成为高于 c++17 的版本标准的一部分的库。
看起来很简单:
- 如果数字大于 10000
- 正常打印,没有数字
%.0f
- 正常打印,没有数字
- 如果一个数字大于 1000
- 在逗号后打印一位
%.1f
- 在逗号后打印一位
- 如果一个数字大于 100
- 在逗号后打印两位数字
%.2f
- 在逗号后打印两位数字
- 如果数字大于 10
2.逗号后3位打印
%.3f
- 如果... 1
- ...
%.4f
- ...
- 其他
%.5f
- 删除前导零
注意四舍五入!前任。数字 9.999999 小于 10,但它会打印为 10.000。正因为如此:
- 首先将所需的最高精度数字 -
%.5f
- 打印到字符串中。 - 然后计算结果字符串. 中逗号前的数字
- 然后在逗号前的 count 个数字而不是实际数字上进行上述比较“如果数字大于 100”。
- Trim 逗号后所需位数的字符串。
即。在打印后处理字符串中正确舍入的数字,而不是在打印前,这样可以防止在转换为字符串时更改数字的任何舍入。
这是一个 C++ 17 版本:
#include <iostream>
#include <charconv>
std::string to6(float f) {
std::string s;
s.resize(10);
auto ec = std::to_chars(s.data(), s.data() + s.size(), f, std::chars_format::fixed);
s.resize(6);
if (s.back() == '.')
s.resize(5);
return s;
}
int main()
{
std::cout << to6(12445.11897784) << std::endl;
std::cout << to6(8846.51548) << std::endl;
std::cout << to6(4.54631888315) << std::endl;
std::cout << to6(7651) << std::endl;
std::cout << to6(0.87457) << std::endl;
return 0;
}
注意:我没有检查错误,因为
Min and max value clamping to prevent truly out of range numbers are handled externally to this problem.