Formatting float without decimals

Discussion in 'C Programming' started by marc, Jan 25, 2014.

  1. marc

    marc Guest


    Is it possible to format a float number, but without displaying decimals
    if it is an integer ?

    For example with "%.2f",
    I get "10.50" for 10.5, but I would like "10" for 10 and not "10.00"

    marc, Jan 25, 2014
    1. Advertisements

  2. marc

    marc Guest

    marc a écrit :
    Well, it seems "%.3g" works fine for my need
    marc, Jan 25, 2014
    1. Advertisements

  3. marc

    Les Cargill Guest

    there's always brute force.

    //#include <stdlib.h>
    #include <stdio.h>

    int main(void)
    static char tehtmp[40];

    const static char * const dotzerozero = ".00";
    float aNumber = 10.0;

    char * const tt = strstr(tehtmp,dotzerozero);

    if (tt != NULL)
    *tt = '\0';
    // or memset(tt,0,strlen(dotzerozero));

    return 0;
    Les Cargill, Jan 25, 2014
  4. float f = 3.142;

    if ((float)((int)f) == f) printf("%d", (int)f);
    else printf("%.2f", f);

    Best regards,
    Rick C. Hodgin
    Rick C. Hodgin, Jan 25, 2014
  5. This can cause an overflow since the range of float is often much wider
    than the range of int. You could convert to long long int, but I think
    there is a better way to do the test: use round (or roundf if a float
    argument is really required).

    I find the extraneous cast and parentheses get in the way of seeing what
    the test does (but I know not everyone agrees). I.e. I'd write

    if ((int)f == f) ...

    Also, the conditional can also be avoided:

    printf("%.*f", roundf(f) == f ? 0 : 2, f);
    Ben Bacarisse, Jan 25, 2014
  6. It's good that you have a solution, but it does not do what you said you
    Ben Bacarisse, Jan 25, 2014
  7. marc

    Kaz Kylheku Guest

    It does; however, he should be using a much higher precision so as not
    to lose significant digits. I would propose, say:

    "%." DBL_DIG "g"

    This approach is exactly how this works:

    $ txr -e '(format t "~s" 3.0)'
    $ txr -e '(format t "~a" 3.0)'

    In the case of "~s", the ".0" is actually *added* deliberately, so that there
    is print/read consistency: the printed representation is a floating-point

    How this works is that there is a sprintf with a "%.*g" conversion, where
    the argument to the * is a variable precision. Its default value is DBL_DIG.

    But, of course %g will use either %f or %e as appropriate, and so we
    can get results like:

    $ txr -p '(format nil "~a" 0.000000000000000001)'

    You can see this in the vformat function in this source file:
    Look for "case 'a'".

    Here is the thing. Although an approximate description of %g is that it works
    by using the formatting of either %f or %e, this is not exactly true: %f does
    not have the %g behavior of removing trailing zeros in the fractional part,
    including, possibly the decimal separator itself. %f also interprets the
    precision parameter differently: precision to %f represents the number of
    digits after the decimal point, whereas %g treats precision as the number of
    significant figures.

    If you must always have output in the form \d+([.]\d+)? where the (\d+)? part
    is omitted if the digits are all zero, and has no trailing zeros, then
    use sprintf to format the number into a buffer, and do some text processing
    on it. You can integrate it into printf like this:

    char scratch[64]; /* or whatever */

    printf("%s\n", format_num(3.0, 5, scratch)); /* up to 5 digits past point */

    format_num returns a pointer into the scratch buffer where it placed the
    formatted number. You can further adjust that with some width and precision
    on the %s.s. format_num can be written so that it (perhaps optionally)
    obliterates the unwanted decimal parts with spaces:

    Hypothetical run:

    /* 1 tells format: "replace trailing stuff with spaces; do not chop". */

    printf("%10s\n", format_num(3.14, 5, 1, scratch));
    printf("%10s\n", format_num(3.0, 5, 1, scratch));

    Output: right adjusted in a field of 10 by %s:

    ___3.14___ <- underscores represent spaces

    The point is that the numbers are still nicely aligned.

    Possible implementation of format_num:

    #include <string.h>
    #include <stdio.h>

    /* scratch is assumed to be 64 bytes */
    char *format_num(double val, int fracdig, int use_spaces, char *scratch)
    int chars = snprintf(scratch, 64, "%.*f", fracdig, val);
    char *dot = strchr(scratch, '.');

    if (chars < 0 || /* old, nonconforming sprintf libraries */
    chars >= 64)
    return "#.#"; /* could not format number */

    if (!dot)
    return scratch;

    fracdig = strlen(dot+1); /* these should be equal, but just in case */

    if (strspn(dot+1, "0") == fracdig) {
    /* decimal is all zeros */
    if (use_spaces)
    memset(dot, ' ', strlen(dot));
    *dot = 0;
    } else {
    int nonzeros = strcspn(dot+1, "0");
    if (nonzeros < fracdig) {
    if (use_spaces)
    memset(dot + 1 + nonzeros, ' ', fracdig - nonzeros);
    *(dot + 1 + nonzeros) = 0;

    return scratch;

    int main(void)
    char sch[64];

    /* pitiful test suite */
    printf("[%10s]\n", format_num(3.0, 5, 1, sch));
    printf("[%10s]\n", format_num(3.14, 5, 1, sch));
    printf("[%10s]\n", format_num(3.0, 5, 0, sch));
    printf("[%10s]\n", format_num(3.14, 5, 0, sch));
    printf("[%10s]\n", format_num(3.0, 0, 1, sch));
    printf("[%10s]\n", format_num(3.14, 0, 1, sch));
    printf("[%10s]\n", format_num(3.0, 0, 0, sch));
    printf("[%10s]\n", format_num(3.14, 0, 0, sch));
    printf("[%10s]\n", format_num(3.14e50, 0, 0, sch));
    printf("[%10s]\n", format_num(3.14e120, 0, 0, sch));

    return 0;


    [ 3 ]
    [ 3.14 ]
    [ 3]
    [ 3.14]
    [ 3]
    [ 3]
    [ 3]
    [ 3]
    [ #.#]
    Kaz Kylheku, Jan 25, 2014
  8. marc

    James Kuyper Guest

    Just use "%.0f".

    "For a, A, e, E, f, F, g, and G conversions ... a decimal-point
    character appears in the result of these conversions only if a digit
    follows it." (
    James Kuyper, Jan 26, 2014
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.