【发布时间】:2019-02-23 22:15:56
【问题描述】:
我正在使用一个应用程序,该应用程序使用std::stringstream 从文本文件中读取由空格分隔的doubles 矩阵。该应用程序使用的代码有点像:
std::ifstream file {"data.dat"};
const auto header = read_header(file);
const auto num_columns = header.size();
std::string line;
while (std::getline(file, line)) {
std::istringstream ss {line};
double val;
std::size_t tokens {0};
while (ss >> val) {
// do stuff
++tokens;
}
if (tokens < num_columns) throw std::runtime_error {"Bad data matrix..."};
}
相当标准的东西。我勤奋地编写了一些代码来制作数据矩阵(data.dat),对每条数据线使用以下方法:
void write_line(const std::vector<double>& data, std::ostream& out)
{
std::copy(std::cbegin(data), std::prev(std::cend(data)),
std::ostream_iterator<T> {out, " "});
out << data.back() << '\n';
}
即使用std::ostream。但是,我发现应用程序无法使用此方法读取我的数据文件(抛出上述异常),尤其是无法读取7.0552574226130007e-321。
我编写了以下显示行为的最小测试用例:
// iostream_test.cpp
#include <iostream>
#include <string>
#include <sstream>
int main()
{
constexpr double x {1e-320};
std::ostringstream oss {};
oss << x;
const auto str_x = oss.str();
std::istringstream iss {str_x};
double y;
if (iss >> y) {
std::cout << y << std::endl;
} else {
std::cout << "Nope" << std::endl;
}
}
我在 LLVM 10.0.0 (clang-1000.11.45.2) 上测试了这段代码:
$ clang++ --version
Apple LLVM version 10.0.0 (clang-1000.11.45.2)
Target: x86_64-apple-darwin17.7.0
$ clang++ -std=c++14 -o iostream_test iostream_test.cpp
$ ./iostream_test
Nope
我也尝试使用 Clang 6.0.1、6.0.0、5.0.1、5.0.0、4.0.1 和 4.0.0 进行编译,但得到了相同的结果。
使用 GCC 8.2.0 编译,代码可以正常工作:
$ g++-8 -std=c++14 -o iostream_test iostream_test.cpp
$ ./iostream_test.cpp
9.99989e-321
为什么 Clang 和 GCC 之间有区别?这是一个clang bug吗,如果不是,应该如何使用C++流来编写可移植的浮点IO?
【问题讨论】:
-
不相关,但变量名称
iss用于输出和oss用于输入是一个奇怪且令人困惑的选择。 -
fyi 1e-320 低于正常范围:en.cppreference.com/w/cpp/language/type
-
@ShafikYaghmour 好吧
1e-320显然在[-DBL_MAX, DBL_MAX]范围内,即使不能准确表示。 -
我举报了libc++ bug。
标签: c++ gcc floating-point clang iostream