Портативный печать экспонента двойной на C++ iostreams с
Я хочу напечатать двойное значение в std::cout
переносимо (GCC, clang, MSVC++), так что выходные данные одинаковы на всех платформах.
у меня проблема с форматированием экспоненты. Следующая программа
#include <iostream>
int main()
{
std::cout << 0.1e-7 << std::endl;
return 0;
}
имеет этот выход с GCC:
1e-08
и следующий вывод с MSVC
1e-008
как я могу сделать так же?
извините, если это глупый вопрос, но я не нашел ответа, поэтому далеко. Все форматирование, похоже, развивается вокруг форматирования всего, что было до мантиссы...
EDIT: выход GCC является 1e-08
не 1e-8
(как заявлено изначально), так что is соответствующий. Извините за беспорядок.
EDIT2: фактически переименован в "мантиссу" в "экспоненту" после замечания Дитмара. также есть раздел в Википедии о мантиссе против значительного.
3 ответов
нет манипулятора, управляющего форматированием экспоненты (я предполагаю, что вы имеете в виду экспоненту, а не мантиссу; кроме того, "официальное" имя, используемое для мантиссы, -значительное). Что еще хуже, я не вижу никакого правила в стандарте C, которое ограничивает форматирование экспоненты. Я понимаю, что речь идет о C++, но для целей форматирования деталей стандарт C++ ссылается на стандарт C.
единственный подход, о котором я знаю это использовать собственный std::num_put<char>
фасет, который форматирует значения по желанию. Затем эта грань будет помещена в std::locale
который в свою очередь imbue()
едь в std::cout
. Потенциальная реализация может использовать значение по умолчанию std::num_put<char>
фасеточных (или snprintf()
что, к сожалению, вероятно, проще), чтобы отформатировать число с плавающей запятой, а затем очистить ведущие нули от экспоненты.
В то время как ответ Дитмара-чистый и, вероятно, единственный действительно портативный ответ, я случайно нашел быстрый и грязный ответ:
MSVC предоставляет _set_output_format
функция, которую вы можете использовать для переключения на "печать экспоненты в виде двух цифр".
следующий класс RAII может быть создан в вашем main()
функция, чтобы дать вам такое же поведение GCC, CLANG и MSVC.
class ScientificNotationExponentOutputNormalizer
{
public:
unsigned _oldExponentFormat;
ScientificNotationExponentOutputNormalizer() : _oldExponentFormat(0)
{
#ifdef _MSC_VER
// Set scientific format to print two places.
unsigned _oldExponentFormat = _set_output_format(_TWO_DIGIT_EXPONENT);
#endif
}
~ScientificNotationExponentOutputNormalizer()
{
#ifdef _MSC_VER
// Enable old exponent format.
_set_output_format(_oldExponentFormat);
#endif
}
};
проблема в том, что Visual C++ не следовал стандарту C99. В Visual C++ 2015,_set_output_format
был удален, так как компилятор теперь следует стандарту:
на
%e
и%E
спецификаторы формата форматируют число с плавающей запятой в виде десятичной мантиссы и экспоненты. The%g
и спецификаторы формата и числа в этой форме в некоторых случаях. В предыдущих версиях CRT всегда генерировал строки с трехзначными показателями. Например,printf("%e\n", 1.0)
печати1.000000e+000
. это было неправильно: C требует, чтобы если экспонента представляется с использованием только одной или двух цифр, то только две цифры должны быть напечатаны.в Visual Studio 2005 добавлен глобальный переключатель соответствия:
_set_output_format
. Программа может вызвать эту функцию с аргументом_TWO_DIGIT_EXPONENT
, чтобы включить соответствующий показатель печати. поведение по умолчанию было изменено на печать экспоненты в соответствии со стандартами режим.
посмотреть нарушение изменений в Visual C++ 2015. Для более старых версий см. ответ @Manuel.
к вашему сведению, в стандарт C99, мы можем читать:
e, E
двойной аргумент, представляющий число с плавающей запятой, преобразуется в стиль [ - ] d.ddd e (+ - ) dd, где есть одна цифра (которая не равна нулю, если аргумент не равен нулю) перед десятичным символом и числом числа после него равно точности; если точность отсутствует, она принимается за 6; если точность равна нулю и флаг # не указан, десятичный знак не отображается. Значение округляется до соответствующего количества знаков. Спецификатор преобразования E создает число С E вместо e, вводящего показатель. экспонента всегда содержит по крайней мере две цифры и только столько цифр, сколько необходимо для представления экспоненты. Если значение равно нулю, показатель равен нулю. Двойной аргумент, представляющий бесконечность или NaN, преобразуется в стиле спецификатора преобразования f или F.
это разница по сравнению с C90, которая не дает никаких указаний относительно требуемой длины экспоненты.
обратите внимание, что последние изменения Visual C++ также касаются печати nan
, inf
etc.