С++, как получить "показатель с одной цифрой" с printf
Есть ли способ печати в научной нотации менее 3-х мест для показательной части числа?
Форматирование 6.1 не влияет на экспоненту, а только на число:
var=1.23e-9;
printf ("%e\n", var);
printf ("%6.1e\n", var);
дает
1.230000e-009
1.2e-009
Я также пробовал это в wxWidgets с форматированием строки, но поведение такое же.
m_var->SetLabel(wxString::Format(wxT("%6.1e"),var));
Я бы хотел иметь 1.2e-9
.
Ответы
Ответ 1
Мне пришлось сделать это много (я пишу анализаторы файлов, а некоторые форматы файлов, такие как NITF, требуют хранения числовых значений в виде строк).
То, что вы делаете, - это эксплойт, основанный на том, что означает базовая математика (научная нотация): означает, что для всех действительных чисел y, y = (x) * 10 ^ (N) для некоторого целого N и некоторого x в диапазоне (-1, 1).
Итак, вы делаете следующее
void PrintScientific(double d)
{
int exponent = (int)floor(log10( fabs(d))); // This will round down the exponent
double base = d * pow(10, -1.0*exponent);
printf("%lfE%+01d", base, exponent);
}
Вы можете добавить все спецификаторы формата, которые вам нужны для управления # символами до, после ".". десятичное место.
НЕ забывайте о шаге округления! Вот как это работает, используя свойства base10 и логарифмы (база 10 здесь):
Пусть y = x * 10 ^ N = >
log (y) = log (x * 10 ^ N) = >
log (y) = log (x) + log (10 ^ N) = > //Из правила журнала "товар"
log (y) = log (x) + N
Так как x находится в диапазоне (-10, 10) - "()" означает эксклюзивную (эксклюзивную), что означает, что log (x) находится в диапазоне (-1, 1). Поэтому, когда мы округляем для целочисленного преобразования, мы отбрасываем вклад "log (x)".
Затем вы можете получить часть "x" от исходного номера, которая позволяет выводить оригинал в любой научной нотации, которую вы хотите использовать.
Ответ 2
Согласно Wikipedia:
Показатель всегда содержит не менее двух цифр; если значение ноль, показатель равен 00. В Windows показатель состоит из трех цифр по умолчанию, например. 1.5e002, но это может быть изменено Специфическая для Microsoft функция _set_output_format.
_ set_output_format
Ответ 3
При стандартном C printf()
это невозможно сделать (и использование трех цифр по умолчанию также кажется неправильным), по крайней мере, на C99 (у меня нет новой версии под рукой). Соответствующая цитата из стандарта C99 находится в пункте 7.19.6.1, пункт 8, форматы e, f:
.... Показатель всегда содержит не менее двух цифр и только столько цифр, сколько необходимо для представления экспоненты. Если значение равно нулю, показатель равен нулю....
Лучше всего поместить этот код в код с помощью большого количества этих выходов, чтобы использовать С++ IOStreams: хотя форматирование по умолчанию такое же, как на C, можно установить настраиваемый фасет в поток std::locale
который делает форматирование так, как вам нужно. Тем не менее, писать код форматирования может быть не совсем тривиальным. Хотя я, вероятно, просто построил бы стандартное преобразование, а затем удалю лишние нули после символа e
.
Ответ 4
Я обнаружил, что Zach отвечает за самый быстрый и простой метод и также применим к любой ОС. Я обнаружил, что для строки "base =" необходимы две модификации для работы для всех чисел. (В противном случае nan, когда экспонента отрицательна в cygwin). Дополнительный оператор печати предназначен только для нейтральной совместимости файлов с патентом. Я бы поддержал его ответ, но я только начал с stackexchange, поэтому у меня нет достаточной "репутации".
void PrintScientific(double d)
{
int exponent = (int)floor(log10( fabs(d))); // This will round down the exponent
double base = (d * pow(10.0, -1*exponent));
if(abs(exponent)<10)
printf("%13.9lfE%+01d", base, exponent);
else
printf("%12.9lfE%+01d", base, exponent);
}
Ответ 5
C/С++ указывает, по крайней мере, две цифры экспоненты с printf("%e",...)
. Для печати только 1 и для работы с Visual Studio, который по умолчанию печатает как минимум 3, необходим дополнительный код.
Рассмотрим IOStreams @Dietmar Kühl
Если код С++ по-прежнему хочет использовать форматы стиля printf()
:
Корректировка значения double
перед вызовом printf()
слишком часто приводит к проблемам округления, короткому замыканию диапазона и общим отказам в случае отказа, например, при работе с log10(0.0)
. Также обратите внимание на большой double
чуть больше мощности 10, где log10()
может оказаться коротким, -0.0
, INF
, NAN
.
В этом случае лучше выполнить пост-обработку строки.
double var = 1.23e-9;
// - 1 . x e - EEEEE \0
#define ExpectedSize (1+1+1+1+1+1+ 5 + 1)
char buf[ExpectedSize + 10];
snprintf(buf, sizeof buf, "%.1e", var);
char *e = strchr(buf, 'e'); // lucky 'e' not in "Infinity" nor "NaN"
if (e) {
e++;
int expo = atoi(e);
snprintf(e, sizeof buf - (e - buf), "%1d", expo);
}
printf("'%6s'\n", buf); // '1.2e-9'
Примечание: %e
любезна для последующей обработки, поскольку его ширина не столь громоздка, как "%f"
. sprintf(buf, "%f", DBL_MAX)
может быть 1000 с char
.