Всегда ли std :: Scientific приводит к нормализованному научному обозначению чисел с плавающей точкой? - PullRequest
0 голосов
/ 29 мая 2018

Научная запись определяет, как числа должны отображаться с использованием знака, числа и показателя степени, но не указывает, что визуализация нормализована.

Пример: -2.34e-2 (нормализованная научная запись) - это то же самое, что и -0.234e-1 (научная запись)

Могу ли я полагаться на следующий код, всегда производящий нормализованный результат? Редактировать: за исключением NAN и INF, как указано в ответах.

template<typename T>
static std::string toScientificNotation(T number, unsigned significantDigits)
{
    if (significantDigits > 0) {
        significantDigits--;
    }
    std::stringstream ss;
    ss.precision(significantDigits);
    ss << std::scientific << number;
    return ss.str();
}

Если да, перечислите раздел в документации / стандарте C ++, указав, что это не платформа / реализация-определены.Поскольку значение 0 также представлено по-разному, я боюсь, что некоторые очень маленькие числа (денормализованные ?!) могут быть визуализированы по-разному.На моей платформе с моим компилятором в настоящее время он работает для std :: numeric_limits :: min (), denorm_min ().

Примечание: я использую это, чтобы найти порядок величины числа, не путаясь со всеми причудливымидетали анализа чисел с плавающей запятой.Я хотел, чтобы стандартная библиотека сделала это для меня: -)

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Да, кроме нуля, бесконечности и NaN.

Стандарт C ++ относится к стандарту C для форматирования, который требует нормализованной научной нотации.

  • [floatfield.manip] / 2

    ios_base& scientific(ios_base& str);
    

    Эффекты: Calls str.setf(ios_­base​::​scientific, ios_­base​::​floatfield).

    Возвращает: str.

  • [ostream.inserters.arithmetic] / 1 (частично)

    operator<<(float val);
    operator<<(double val);
    operator<<(long double val);
    

    Эффекты: Классы num_­get<> и num_­put<> обрабатывать зависящее от локали числовое форматирование и анализ. Эти функции вставки используют значение locale для выполнения числового форматирования.Когда val имеет тип ..., double, long double, ..., преобразование форматирования происходит так, как будто выполняется следующий фрагмент кода:

    bool failed = use_facet<
      num_put<charT, ostreambuf_iterator<charT, traits>>
        >(getloc()).put(*this, *this, fill(), val).failed();
    

    Когда val имеет значениетипа float преобразование форматирования происходит так, как будто выполняется следующий фрагмент кода:

    bool failed = use_facet<
      num_put<charT, ostreambuf_iterator<charT, traits>>
        >(getloc()).put(*this, *this, fill(),
          static_cast<double>(val)).failed();
    
  • [facet.num.put.virtuals] / 1: 5.1 (частичное)

    • Этап 1:

      Первым действием этапа 1 является определение спецификатора преобразования.В таблицах, описывающих это определение, используются следующие локальные переменные

      fmtflags flags = str.flags();
      fmtflags floatfield = (flags & (ios_base::floatfield));
      

      Для преобразования из типа с плавающей запятой функция определяет спецификатор преобразования с плавающей запятой, как указано в таблице 70.

      Таблица 70 - Преобразования с плавающей точкой

      | State                                            | stdio equivalent |
      | ------------------------------------------------ | ---------------- |
      | floatfield == ios_­base​::​scientific && !uppercase | %e               |
      | floatfield == ios_­base​::​scientific               | %E               |
      

      Представления в конце этапа 1 состоят из char , которые будут напечатаны вызовом printf(s, val), гдеs - это спецификатор преобразования, определенный выше.

  • C11 n1570 [7.21.6.1]: 8,4

    • e , E

      Аргумент double, представляющий число с плавающей запятой, преобразуется в стиль [-] d.ддд е ± дд , где есть одна цифра (ненулевая, если аргумент ненулевой) перед символом десятичной точки и числомцифр после того, как он равен точности;если точность отсутствует, она принимается за 6;если точность равна нулю и флаг # не указан, символ десятичной точки не отображается.Значение округляется до соответствующего количества цифр.Спецификатор преобразования E создает число с E вместо e , представляющим показатель степени.Экспонента всегда содержит не менее двух цифр и только столько цифр, сколько необходимо для представления экспоненты. Если значение равно нулю, показатель степени равен нулю.

      A double аргумент, представляющий бесконечность или NaN, преобразуется в стиле f или F спецификатор преобразования.

0 голосов
/ 29 мая 2018

Могу ли я полагаться на следующий код, всегда выдающий нормализованный результат?

Нет никаких гарантий, нет.Проще говоря: Стандарт не налагает столь же сильную гарантию, как хотелось бы.

std::scientific цитируется только по следующим соответствующим частям:

  1. [floatfield.manip]:2

    ios_base& scientific(ios_base& str);  
    

    Эффекты : вызовы str.setf(ios_­base​::​scientific, ios_­base​::​floatfield).
    Возвраты : str.

  2. Таблица 101 - эффекты fmtflags

    | Element    | Effect(s) if set                                       |
    | ...        | ...                                                    |
    | scientific | generates floating-point output in scientific notation |
    | ...        | ...                                                    |
    
...