c ++, как получить "однозначный показатель" с помощью printf - PullRequest
12 голосов
/ 08 января 2012

Есть ли способ напечатать в научной записи менее 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.

Ответы [ 5 ]

12 голосов
/ 08 января 2012

Согласно Википедии :

Показатель степени всегда содержит как минимум две цифры;если значение равно нулю, показатель степени равен 00. В Windows показатель степени содержит три цифры по умолчанию, например, 1.5e002, но это можно изменить с помощью функции _set_output_format, характерной для Microsoft.

_set_output_format

6 голосов
/ 18 июня 2013

Мне приходилось делать это много (я пишу парсеры файлов, и некоторые форматы файлов, такие как NITF, требуют, чтобы вы хранили числовые значения в виде строк).

То, что вы делаете, это эксплойт, основанный на том, какие базовые10 математика (научное обозначение) действительно означает: это означает, что для всех действительных чисел 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 и logarithms (base 10 здесь):Пусть у = х * 10 ^ N =>log (y) = log (x * 10 ^ N) =>log (y) = log (x) + log (10 ^ N) => // Из журнала "product" rulelog (y) = log (x) + N

Поскольку x находится в диапазоне (-10, 10) - «()» означает исключительный (исключающий), то есть log (x) находится в диапазоне (-1, 1).Поэтому, когда мы округляем число для целочисленного преобразования, мы отбрасываем вклад «log (x)».Затем вы можете получить часть «x» из исходного числа, что позволит вам вывести оригинал в любой научной нотации, которую вы хотите использовать.

4 голосов
/ 08 января 2012

Со стандартным C printf() это невозможно сделать (и использование трех цифр по умолчанию также кажется неправильным), по крайней мере, в C99 (у меня нет более новой версии под рукой). Соответствующая цитата из стандарта C99 в пункте 7.19.6.1, форматы e, f:

.... Показатель степени всегда содержит не менее двух цифр и только столько цифр, сколько необходимо для представления показателя. Если значение равно нулю, показатель степени равен нулю. ...

Лучше всего встраивать это [переносимо] в код, использующий множество этих выходных данных, - использовать потоки IOS C ++: хотя форматирование по умолчанию такое же, как и в C, можно установить собственный фасет в std::locale потока который делает форматирование так, как вам нужно. Тем не менее, написание кода форматирования может быть не совсем тривиальным. Хотя я, вероятно, просто построю стандартное преобразование, а затем уберу лишние нули после символа e.

1 голос
/ 05 февраля 2015

Я нашел ответ Зака ​​самым быстрым и простым методом, который также применим к любой ОС.Я обнаружил, что в строке «base =» требовалось две модификации, чтобы она работала для всех чисел.(В противном случае Нана, когда показатель отрицателен в Cygwin).Дополнительный оператор печати предназначен только для совместимости файлов с нейтральным патраном.Я бы проголосовал против его ответа, но я только начал на стек-обмене, поэтому у меня нет достаточной «репутации».

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);
}
0 голосов
/ 10 июля 2015

C / C ++ задает как минимум две цифры степени с printf("%e",...). Чтобы печатать только 1 и работать с Visual Studio, которая по умолчанию печатает как минимум 3, требуется дополнительный код.

Рассмотрим IOStreams @ Dietmar Kühl

Если код C ++ все еще хочет использовать форматы стиля 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.

...