Я использую приложение, которое использует std::stringstream
для чтения матрицы пробелов, отделенных double
s от текстового файла.Приложение использует код, похожий на:
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, и если нет, то как использовать потоки C ++ для записи переносимых операций ввода-вывода с плавающей запятой?