Почему std :: istringstream генерирует неправильные результаты, не поднимая флаг failbit? - PullRequest
0 голосов
/ 02 января 2019

Когда я конвертирую string, который содержит long double в float или double, std::istringstream не поднимает флаг сбоя в QNX .

Ниже приведен демонстрационный код:

#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <limits>

int main(){
    const long double originaldNumber = std::numeric_limits<long double>::max() / 2;
    float floatNumber;
    std::string numberString = std::to_string(originaldNumber);

    //From string to long double
    std::istringstream iss(numberString);
    iss >> floatNumber;

    if (iss.fail())
        std::cout<< "iss failed \n";

    std::cout<< std::setprecision(30) << originaldNumber << "\n";
    std::cout<< std::setprecision(30) << floatNumber << "\n";

    return 0;
}

Вывод в linux:

 iss failed 
 5.94865747678615882510631926515e+4931
 3.40282346638528859811704183485e+38

Выход в QNX:

5.94865747678615882510631e+4931
inf

Версия QNX: 7.0.3 2018/09/18-00:28:50EDT x86pc x86_64.
Набор инструментов: gcc_ntox86_64

1 Ответ

0 голосов
/ 02 января 2019

Согласно cppreference.com, вот что происходит:

std::istringstream::operator<<(float&):

(5) извлекает значение с плавающей запятой, вызывая std::num_get::get()

std::num_get::get()

Этап 3: преобразование и хранение

Входные данные анализируются как если бы std::strtof

В любом случае при сбое функции преобразования std::ios_base::failbit присваивается err.

std::strtof

Возвращаемое значение

Значение с плавающей запятой, соответствующее содержимому строки в случае успеха.Если преобразованное значение выходит за пределы диапазона соответствующего типа возврата, возникает ошибка диапазона и возвращается HUGE_VAL, HUGE_VALF или HUGE_VALL.Если преобразование не может быть выполнено, возвращается 0 и *str_end устанавливается на str.

HUGE_VALF

HUGE_VALF Расширяется до положительного выражения с плавающей запятой, которое указывает на переполнение


В вашем случае ясно, что std::strtof с 5.94...e+4931 переполнит float, оно должно вернуть HUGE_VALF, что является значением ошибки для этой функции.Под linux:

float const have_overflown = std::strtof("1e307", nullptr);
std::cout << "equals HUGE_VALF: " << std::boolalpha
          << (have_overflown == HUGE_VALF) << '\n';     // true
std::cout << "string repr: " << have_overflown << '\n'; // inf

Демонстрация в реальном времени

Поскольку std::strtof эффективно возвращает HUGE_VALF для переполненных значений, бит сбоя потока, вызывающего его , должен будет установлено, как указано в спецификации std::istringstream::operator<<(float&).

QNX не соответствует этому требованию.Вы можете попытаться проверить, где в цепи произойдет сбой.


В соответствии с QNX doc на strtof:

Если правильное значение будетвызвать переполнение, плюс или минус HUGE_VAL возвращается в соответствии со знаком, и errno устанавливается в ERANGE.

Вы можете проверить errno против ERANGE в дополнение к проверке битов сбоя потока:

errno = 0;
iss >> floatNumber;
if (iss.fail() || errno == ERANGE) {
    // fail
}

Наконец, если ваша реализация не соответствует своей собственной документации, как вы говорите, id делает это в разделе комментариев, вы можете проверить floatNumber против HUGE_VALF, чтобы обнаружить переполнения.

...