在C++中将浮点数的默认打印精度恢复为默认值

34

我想在C++中控制double类型的精度进行比较,然后再恢复默认精度。

我打算使用setPrecision()来设置精度。是否有语法可以将精度设置回默认值?

我的代码大致如下:

std::setPrecision(math.log10(m_FTOL));

我做了一些事情,接着我想立即回到默认的双精度比较操作。

我进行了如下修改,但仍然存在一些错误。

std::streamsize prec = std::ios_base::precision();
std::setprecision(cmath::log10(m_FTOL));

我编译时使用了 cmath 的 false 以及 std::ios_base 的 false。请问能否帮忙解决?


你的答案在这里吗?点击链接 - Hindol
5个回答

43

在更改精度之前,您可以使用 std::ios_base::precision 获取精度,然后稍后将其更改回来。

您可以通过以下示例看到它的实际效果:

#include <ios>
#include <iostream>
#include <iomanip>

int main (void) {
    double pi = 3.141592653590;

    std::streamsize ss = std::cout.precision();
    std::cout << "Initial precision = " << ss << '\n';

    std::cout << "Value = " << pi << '\n';

    std::cout.precision (10);
    std::cout << "Longer value = " << pi << '\n';

    std::cout.precision (ss);
    std::cout << "Original value = " << pi << '\n';

    std::cout << "Longer and original value = "
        << std::setprecision(10) << pi << ' '
        << std::setprecision(ss) << pi << '\n';

    std::cout << "Original value = " << pi << '\n';

    return 0;
}

输出结果为:

Initial precision = 6
Value = 3.14159
Longer value = 3.141592654
Original value = 3.14159
Longer and original value = 3.141592654 3.14159
Original value = 3.14159

以上代码展示了两种设置精度的方式,第一种是通过调用std::cout.precision (N)方法,第二种是使用流操作符std::setprecision(N)

但是您需要记住,精度是用于通过流输出值的,它不会直接影响与这些值进行比较的代码,例如:

if (val1 == val2) ...

换句话说,即使输出可能是3.14159,但该值本身仍然是完整的3.141592653590(当然,受正常浮点限制的影响)。
如果您想这样做,您需要检查它是否足够接近而不是相等,使用以下代码:
if ((fabs (val1 - val2) < 0.0001) ...

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Mike Bell
@Mike,根据我的更新答案,那应该也可以工作。请仔细阅读更改内容,如果您仍然无法使其正常工作,您可能需要在这里提出问题。 - paxdiablo
如果我将其推送到ofstream而不是cout,它的工作方式是否有任何区别?实际上,我还没有使用cout进行测试——我正在写入文件。也许这就是问题所在。 - Mike Bell
@Mike,没有区别,应该完全一样。事实上,我刚刚测试过了。将<iostream>替换为<fstream>,在main函数的第一条语句中执行std::ofstream ofs("output.txt", std::ofstream::out);,在return之前执行ofs.close();,并将所有的std::cout改为ofs。然后output.txt文件将会保存与答案代码屏幕上看到的完全相同的内容。 - paxdiablo
@Mike,尝试在你的系统上使用我的代码做同样的事情,如果你没有得到相同的结果,请发布一个带有你的代码的问题。这样你会得到更广泛的回应。 - paxdiablo
显示剩余2条评论

8

使用C++20 std::format{:.2} 代替 std::setprecision

最终,一旦你能使用它,这将是更优的选择:

#include <format>
#include <string>

int main() {
    std::cout << std::format("{:.3} {:.4}\n", 3.1415, 3.1415);
}

预期输出:

3.14 3.145

所以这将完全克服修改 std::cout 状态的疯狂。

现有的 fmt 库实现了它,早在它正式获得支持之前:https://github.com/fmtlib/fmt 在 Ubuntu 22.04 上安装:

sudo apt install libfmt-dev

修改源代码以替换:

  • <format><fmt/core.h>
  • std::formatfmt::format

main.cpp

#include <iostream>

#include <fmt/core.h>

int main() {
    std::cout << fmt::format("{:.3} {:.4}\n", 3.1415, 3.1415);
}

并且使用以下命令进行编译和运行:

g++ -std=c++11 -o main.out main.cpp -lfmt
./main.out

输出:

3.14 3.142

参见:

在C++20之前/fmt:::使用std::ios::copyfmt保存整个状态

在这些情况下,您可能还想使用std::ios::copyfmt恢复整个以前的状态,如恢复操作std::cout后的其状态所述。

main.cpp

#include <iomanip>
#include <iostream>

int main() {
    constexpr float pi = 3.14159265359;
    constexpr float e  = 2.71828182846;

    // Sanity check default print.
    std::cout << "default" << std::endl;
    std::cout << pi << std::endl;
    std::cout << e  << std::endl;
    std::cout << std::endl;

    // Change precision format to scientific,
    // and restore default afterwards.
    std::cout << "modified" << std::endl;
    std::ios cout_state(nullptr);
    cout_state.copyfmt(std::cout);
    std::cout << std::setprecision(2);
    std::cout << std::scientific;
    std::cout << pi << std::endl;
    std::cout << e  << std::endl;
    std::cout.copyfmt(cout_state);
    std::cout << std::endl;

    // Check that cout state was restored.
    std::cout << "restored" << std::endl;
    std::cout << pi << std::endl;
    std::cout << e  << std::endl;
    std::cout << std::endl;
}

GitHub源代码

编译并运行:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

输出:

default
3.14159
2.71828

modified
3.14e+00
2.72e+00

restored
3.14159
2.71828

在Ubuntu 19.04和GCC 8.3.0上进行了测试。


5

在进行必要的修改精度操作后,您需要跟踪当前精度并重置回相同的精度。为此,您可以使用 std::ios_base::precision

streamsize precision ( ) const;
streamsize precision ( streamsize prec );

第一种语法返回流的当前浮点精度字段的值。
第二种语法还可以将其设置为新值。

3

setprecision()只适用于输出操作,不能用于比较操作。

要比较浮点数a和b,你需要显式地这么做:

  if( abs(a-b) < 1e-6) {   
  }
  else {
  } 

3

你可以使用cout << setprecision(-1)


嗯,它可以工作但没有文档记录。 - 4LegsDrivenCat

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