tags:

views:

338

answers:

6

If the float contains "5.12345", display only "5.1"

If the float contains "5.0", display only 5 (drop the ".0")

If the float contains "5.0176", display only 5 (drop the ".01")

I thought printf() could do something like this... but now I can't seem to get it to work.

A: 

Not the way you've described it, no. If you want conditional decimal places, you have to do it yourself.

it's been a while since I've mucked with printf formats, but this appears to work in most cases

char *BuildConditionalFormat(double val)
{
    int tenths = (int)(val * 10) % 10;
    if (tenths == 0)
        return ".0f";
    return ".1f";
}

/* test rig */
float f = 5.0;
printf(BuildConditionalFormat(f), f); /* -> 5 */
f = 5.13;
printf("\n");
printf(BuildConditionalFormat(f), f); /* -> 5.1 */
printf("\n");

This abides by your rules, but will also provide an interesting lesson in why floating point stinks because 5.1 -> 5. Why? Because 5.1 doesn't represent cleanly (on my machine) as a float - it's 5.09999 and some more change.

Chances are you need to learn about floor() and ceil() too...

plinth
+1  A: 

printf() can use formatting strings. Look at the width and precision options of the formatting strings:

printf("%.1f", 5.12345f);

This will print 5.1.

Unfortunately, it does not have the ability to automatically determine, without guidance, what to display. (For example, your last option there is unclear to me - why should it drop the ".0176", without you telling it you want no decimal points?)

Reed Copsey
That won't drop .0 off of say 5.0 fyi.
Daniel
but it will print 5.0 in case if 5.0. OP wants to print 5 in that case.
N 1.1
@Dana: I'm not sure that's true. Look at the OP's first option - they want 5.1 for 5.12345 - no 0 involved there...
Reed Copsey
I figured I'd show what IS possible using printf - and the OP can clarify if that isn't the intended results.
Reed Copsey
@Reed: It needs to do -all- of those cases, not just the first one.
Daniel
@Daniel: As I said in my post, you have to provide it guidance via the width+precision. It CAN handle any of these cases, but different format strings are required for each.
Reed Copsey
A: 

You can tell printf to print specified number of digits after '.' ,but if you want to differ the format basing on the value you have to write code to distinguish cases interesting for you.

pajton
+1  A: 

None of the formatting operators support this, however you could filter the float through sprintf() first, then truncate the string where appropriate. This saves you the trouble of converting the float to a string and the logic to do the rest is easy.

Dana the Sane
+3  A: 

You can get kind of close to the results you want using "%g"

#include <stdio.h>

int main(int argc, char* argv[])
{
        printf("%.6g\n", 5.12345f);
        printf("%.6g\n", 5.0f);
        printf("%.6g\n", 5.0176f);
        return 0;
}

Output:

5.12345
5
5.0176

"%g" will remove trailing zeros.

Jason
`%.2g` would pass all three of the OP's tests.
Max Shawabkeh
@Max, i've looked into the manpage. If he says `%.2g`, and prints `100`, he gets `1.00e+02` (if the exponent would be greater or equal the precision, scientific style is used by `%g`). I think that may not be what he wants.
Johannes Schaub - litb
A: 

Sounds like you want to print 1 decimal place, and if that place is 0, drop it. This function should work fine:

// prints the float into dst, returns the number
// of chars in the manner of snprintf. A truncated
// output due to size limit is not altered.
// A \0 is always appended. 
int printit(float f, char *dst, int max) {
  int c = snprintf(dst, max, "%.1f", f);

  if(c > max) {
    return c;
  }

  // position prior to '\0'
  c--;

  while(dst[c] == '0') {
    c--;
    if(dst[c] == '.') {
      c--;
      break;
    }
  }
  dst[c + 1] = '\0';  
  return c + 1;
}

int main(void) {
  char num1[10], num2[10], num3[10];
  printit(5.12345f, num1, 10);
  printit(5.0f, num2, 10);
  printit(5.0176f, num3, 10);
  printf("%s\n%s\n%s\n", num1, num2, num3);
}
Johannes Schaub - litb