Formatting float without decimals

M

marc

Hello,

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"

Thanks.
 
M

marc

marc a écrit :
Hello,

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"

Thanks.

Well, it seems "%.3g" works fine for my need
 
L

Les Cargill

marc said:
Hello,

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"

Thanks.


there's always brute force.


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

int main(void)
{
static char tehtmp[40];
sprintf(tehtmp,"%.2f",aNumber);

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));
}

printf("%s",tehtmp);
return 0;
}
 
R

Rick C. Hodgin

Hello,

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"

float f = 3.142;

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

Best regards,
Rick C. Hodgin
 
B

Ben Bacarisse

Rick C. Hodgin said:
float f = 3.142;

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

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);
 
B

Ben Bacarisse

marc said:
marc a écrit :

Well, it seems "%.3g" works fine for my need

It's good that you have a solution, but it does not do what you said you
wanted!
 
K

Kaz Kylheku

It's good that you have a solution, but it does not do what you said you
wanted!

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)'
3.0
$ txr -e '(format t "~a" 3.0)'
3

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
number.

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)'
1e-18

You can see this in the vformat function in this source file:
http://www.kylheku.com/cgit/txr/tree/stream.c
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
___3______

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));
else
*dot = 0;
} else {
int nonzeros = strcspn(dot+1, "0");
if (nonzeros < fracdig) {
if (use_spaces)
memset(dot + 1 + nonzeros, ' ', fracdig - nonzeros);
else
*(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;
}

Output:

[ 3 ]
[ 3.14 ]
[ 3]
[ 3.14]
[ 3]
[ 3]
[ 3]
[ 3]
[314000000000000011495964840544938881872998818643968]
[ #.#]
 
J

James Kuyper

Hello,

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"

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." (7.21.6.1p6)
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,817
Latest member
AdalbertoT

Latest Threads

Top