【问题标题】:Formatting floats: returning to default格式化浮点数:返回默认值
【发布时间】:2019-04-01 12:27:41
【问题描述】:

在返回“默认格式”的意义上,我遇到了浮点值的格式问题。 假设我有 2 个花车:

float f1 = 3.0f, f2 = 1.5f;
std::cout << f1 << " - " << f2 << "\n";

将显示为:3 - 1.5

现在,出于某种原因,我需要在 std::cout 上设置精度(用于其他打印):

cout << std::precision(2);

如果我再次打印我的两个浮点数,这将导致:3.00 - 1.50

现在我想恢复默认格式。在 C++11 之前,这似乎很困难(或者是吗?)。但是,谢谢,我现在得到了这个新标志: std::defaultfloat。让我们试试:

std::cout << std::defaultfloat << f1 << " - " << f2;

将打印:3 - 1.50。很好。

哦,等一下。说我有:

float f1 = 444.0f, f2 = 444.5f;

默认打印将显示:444 - 444.5

设置精度(和“固定”):

cout << std::precision(2) << std::fixed;

将显示:444.00 - 444.50

但回到“默认”:

std::cout << std::defaultfloat << f1 << " - " << f2;

将打印:4.4e+02 - 4.4e+02(自动切换到科学格式)。而且,如果您想知道,附加“固定”标志将保持先前分配的精度,因此不会返回到原始设置。

问题:如何回到默认模式?

FWIW,live code is here.

编辑:此问题已被标记为欺骗,但linked answer 没有提供问题的答案,它只提到如何获得当前精度。

编辑 2:根据要求,这里是演示问题的完整代码:

int main()
{
    float f1 = 444.5f, f2=443.0f;
    std::cout << f1 << " - " << f2 << "\n";
    std::cout << std::fixed << std::setprecision(2);
    std::cout << f1 << " - " << f2 << "\n";
    std::cout << std::defaultfloat;
    std::cout << f1 << " - " << f2 << "\n";
}

结果:

444.5 - 443
444.50 - 443.00
4.4e+02 - 4.4e+02

【问题讨论】:

  • 我不确定你为什么会遇到这个问题,但是在 C++11 之前就已经存在并且现在仍然可以使用的一种解决方案是 Boost 的 I/O Stream State Saver 库:@ 987654324@
  • 谢谢!不知道那个(Boost中有很多东西......),我会试一试。但是标准库不应该这样做吗?或者,至少,指定一个设置说“如果小数部分为 0,则打印为整数”?
  • @JohnZwinck 好的,检查了另一个答案。但是,它并没有真正回答这里的问题(尽管它给了我一个提示)。您能否重新打开,以便我可以添加我自己同时提出的答案。
  • 这将改善问题,让MCVE 显示问题中的不良行为,而不是一系列 sn-ps 和/或外部 MCVE 链接。此外,您不需要展示正常工作的案例。
  • @M.M 正确,我编辑了问题。

标签: c++ floating-point precision iomanip


【解决方案1】:

在 C++20 中,您可以使用 std::format,它是一个无状态 API。特别是,在一个调用中指定精度不会影响另一个调用:

float f1 = 444.0f, f2 = 444.5f;
std::cout << std::format("{} - {}\n", f1, f2);
// Output: 444 - 444.5
std::cout << std::format("{:.2f} - {:.2f}\n", f1, f2);
// Output: 444.00 - 444.50
std::cout << std::format("{} - {}\n", f1, f2);
// Output: 444 - 444.5

std::format 尚未广泛使用,但您可以使用the {fmt} library,同时std::format 基于。它还提供了一个print函数,结合了格式化和I/O:

float f1 = 444.0f, f2 = 444.5f;
fmt::print("{} - {}\n", f1, f2);
// Output: 444 - 444.5
fmt::print("{:.2f} - {:.2f}\n", f1, f2);
// Output: 444.00 - 444.50
fmt::print("{} - {}\n", f1, f2);
// Output: 444 - 444.5

免责声明:我是 {fmt} 和 C++20 std::format 的作者。

【讨论】:

  • 感谢您的回答。是的,我看过,但我不是粉丝。这种范式(在函数调用中嵌入要打印的对象)对我来说听起来确实像是回到 C(printf(...),尽管我知道它比这要好得多,人们可能会采用它。我真的很喜欢溪流,它们很方便。但无论如何,感谢您的贡献!
【解决方案2】:

std::defaultfloat 不会重置精度。 (不要问我为什么)。您可以将其重置为定义为 6 的默认值:

std::cout << std::defaultfloat << std::setprecision(6) << f1 << " - " << f2;

或者,您可以在操作之前保存整个流状态并在之后恢复它;请参阅this thread

【讨论】:

  • 是的,就是这样。我不清楚的是,在“默认”模式下(即在流式传输 defaultfloat 之后),您需要将精度设置为比总位数更大的位数的数字,以避免点。
【解决方案3】:

std::precision 指定 cout 显示的精度,当你改变格式时它不会改变。

因此,当您设置 std::precision(2) 时,它指定以下所有格式都将应用该精度显示。

固定格式应用精度,因为 n 是小数点后的位数。 默认浮点格式应用精度作为要显示的最大总位数。

它不会重置精度值。

供参考: ios_base::precision

【讨论】:

  • 是的,我明白了,谢谢。但是……你对我的问题有任何想法吗? (或一种设置原始格式的方法)。
  • 查看参考以了解精确度。它确实向您展示了如何获得当前精度,因此您应该能够很容易地弄清楚如何获得它。但作为一种快捷方式,默认精度值为 6。
【解决方案4】:

您可以在原始std::ostreamstd::streambuf 上创建自己的std::ostream,并在这个新的个人std::ostream 上设置格式。

#include <iostream>
#include <ostream>
#include <iomanip>

float const f1 = 3.0f, f2 = 1.5f;

void proc1() {
    std::ostream out(std::cout.rdbuf());
    out << "Inside proc1(), floats are printed like: " << std::setprecision(2) << std::fixed << f1 << " and " << f2 << '\n';
}

int main() {
    std::cout << "Inside main(), floats are printed like: " << f1 << " and " << f2 << '\n';
    proc1();
    std::cout << "Back in main(), floats are printed like: " << f1 << " and " << f2 << '\n';
}

此代码将打印:

Inside main(), floats are printed like: 3 and 1.5
Inside proc1(), floats are printed like: 3.00 and 1.50
Back in main(), floats are printed like: 3 and 1.5

你可以去那里试试:http://coliru.stacked-crooked.com/a/4994c3f604b63d67

基于另一个std::streambuf 创建一个std::ostream 是正确的,因为std::ostream 的析构函数不会触及其分配的std::streambuf。见:https://en.cppreference.com/w/cpp/io/basic_ostream/%7Ebasic_ostream

【讨论】:

  • 谢谢,很好的答案!是的,没错,您始终可以复制流并为其分配特定格式;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多