2014-02-21 2 views
1

У меня проблема с fprintf. Я хочу использовать как можно больше места в одном столбце, но это означает изменение количества десятичных чисел с плавающей запятой. У меня есть немного проблемы, чтобы описать это так, может быть, просто, например:fprintf, который использует постоянное пространство

0.0
0.123456 
1.234567 
12.34567 
123.4567 

Я пытался играть с г и F вариантов, но он не работает для меня (то есть такие вещи, как %8.6g или %8.6f).

+0

Можете ли вы предоставить нам лучший пример того, что вы хотите? – JMBise

+0

Переформатирование вашего вопроса (включая кавычки) для показа желаемого макета может помочь прояснить ваш запрос и, таким образом, получить помощь. –

+0

Не может быть единой спецификации формата, которая может делать то, что вы хотите, поэтому вам может потребоваться выбрать во время выполнения из нескольких альтернатив в зависимости от значения, которое будет напечатано. Я думаю, что '% .7g' для чисел> = 1.0 и'% 5f' для чисел <= 1.0 будет делать то, что вы хотите. –

ответ

3

Это является хитрым, чтобы выжить угловые случаи.

С различными спецификаторами точности изменяется число цифр левой стороны десятичной точки.

printf("%.3f", 9.996) --> "9.996"; 
printf("%.2f", 9.996) --> "10.00"; // Same print width with different precision. 

Учитывая различные режимы округления, +/- числа, NaN, INF, и детали типичного двоичного представления чисел с плавающей точкой, пытаясь предсказать ширину printf() для заданного числа с плавающей точкой, в лучше всего, приближение. Вместо того, чтобы не думать printf(), просто sprintf() с лучшей точностью догадки. Используйте значение sprintf() и при необходимости отрегулируйте точность.

Решение:

  1. ширина Эстимейт.
  2. Печать в буфер.
  3. При необходимости отрегулируйте.

.

#include <float.h> 
int fprintf_Width(FILE *outf, double a, int width) { 
    // Subtract 2 for a potential leading "0." 
    int prec = width - 2; 
    if (prec < 0 || prec > 100 /* TBD upper bound */) 
    return 0; // `width` out of range 

    // By some means, determine the approximate precision needed. 
    char buf[1 + 1 + DBL_MAX_10_EXP + 1 + prec + 1]; 
    int len = sprintf(buf, "%#.*f", prec, a); 
    prec -= len - width; 
    if (prec < 0) 
    return 0; // `a` too big 

    // Try it out 
    len = sprintf(buf, "%#.*f", prec, a); 

    // Adjust as needed 
    if (len > width) { 
    prec--; 
    if (prec < 0) 
     return 0; // `a` too big 
    sprintf(buf, "%#.*f", prec, a); 
    } 
    len = fprintf(outf, "%s", buf); 
    return len; 
} 
+0

Спасибо, за исключением того, что у моего компилятора была проблема с объявлением 'char buf [...', работала, как ожидалось. –

0

Квитирование: Этот подход не с определенными номерами с определенной шириной спецификацией, как это указано в комментариях.

Одна вещь, которую вы могли бы сделать это, чтобы вычислить количество цифр до десятичной точки, а затем использовать printf Precision Specification укоротить цифры, которые сделали бы число слишком долго.

  • Вы можете создать пользовательскую функцию, принимая FILE указатель для использования с fprintf, float nubmer, который вы хотите напечатать и нужное количество символов, которые вы хотите иметь; 3 аргумента.

  • Следующее, что вам нужно сделать, это определить количество цифр до десятичной точки. Имея новую переменную int и положив в нее float, разделите ее на int на 10 s, пока она не станет нулевой. Но будьте осторожны, 0.0 также имеет одну цифру до десятичной точки, хотя ее оценка int не отображает ее.

  • Тогда все, что вам нужно сделать, это уменьшить ширину, получаемую количеством цифр до десятичной точки, плюс 1 для самой десятичной точки (или, скорее, минус в этом случае), и это будет ваше Прецизионная спецификация для fprintf, которую вы будете использовать.

Таким образом, в конце концов, ваш fprintf должен выглядеть примерно так с этим методом:

fprintf(fp, "%.*f", Width - digitsbeforeDpoint - 1); 

Вот пример того, что я сделал, работая, насколько я могу проверить. Он также имеет некоторые дополнительные меры предосторожности, чтобы убедиться, что каждый вход является разумным и уверяя, что поплавок дается квалифицирован, чтобы распечатать количество цифр вы желаете:

#include <stdio.h> 

void fixdLengthfprintf(FILE * _File, float a, int width) { 
    if (!_File) return; 
    if (width < 3) return; 

    int b = a; 
    do { 
     width--; 
     b /= 10; 
    } while (b); 
    width--; 

    if (width > 0) fprintf(_File, "%.*f\n", width, a); 
} 

int main() { 

    float numbers[7] = { // prints as: 
     1.123456,   // 1.123456 
     12.1234567,   // 12.12346 (apparently rounded) 
     123456.,  // 123456.0 (heavily rounded) 
     1234567., // doesn't get printed 
     12345678., // doesn't get printed 
     123456789., // doesn't get printed 
     0.123456789,  // 0.123457 
    }; 

     // I don't allow them to get printed because else they'd look like: 
     // 1.123456 
     // 12.12346 
     // 123456.0 
     // 1234567 
     // 12345678.000000 
     // 123456792.000000 
     // 0.123457 

    for (int i = 0; i < 7; i++) fixdLengthfprintf(stdout, numbers[i], 8); 

    fflush(stdin); 
    getchar(); 
    return 0; 
} 
+0

Этот подход терпит неудачу, когда 'a' находится под степенью 10 и' width' примерно равным или меньше, чем 'FLT_DECIMAL_DIG' из-за' fprintf() ', отображающего округленные числа, которые сдвигают десятичную точку. Расчет 'b' не учитывает этого. Попробуйте 'fixdLengthfprintf (stdout,, 999.99994, 6)'. – chux

+0

@chux Это правда и хороший пример; и я сдаюсь, я не смог исправить эту конкретную проблему любым упрощенным способом, не меняя метод, с которым я обращаюсь. – ThoAppelsin

Смежные вопросы