I am just wondering if there is a way to make printf() handle floats sanely.
For example I have the numbers 6 and 73.03, I would like printf() to print '6' and '73.03'. Instead of '6.000000' and '73.030000' or '6' and '73', or '6.00' and '73.03'.
Is there a printf() modifier to make this happen or will I have to calculate this myself?
Yes, there is.. do a search on google. I think you want to look for %f, %0, etc..
%02f gives 2 decimal numbers padded with 0. %2f gives up to 2 decimal numbers without padding.
Richard Phipps, I have already done that to no avail.
ReyBrujo, %2f still printed out 6 decimal places. %02f did the same.
Wait, sorry, %.2f instead of %2f
That's closer, but it always prints 2 decimal places regardless of the actual value.
I was going to give you some tips on building a function to do that, but I wasn't totally sure how to do it, so I tried to first make that function and then help. But now that I have a semi-working thingie in my text editor, I'd feel bad not to give it out: (with a smell test program, which has memory leaks
)
| 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <string.h> |
| 4 | |
| 5 | |
| 6 | |
| 7 | char * floatToSane(float x); |
| 8 | |
| 9 | int main(void) { |
| 10 | printf("%f\n",(float)32); |
| 11 | printf("%s\n",floatToSane((float)32)); |
| 12 | printf("%f\n",(float)0.32); |
| 13 | printf("%s\n",floatToSane((float)0.32)); |
| 14 | |
| 15 | return 0; |
| 16 | } |
| 17 | |
| 18 | #define BUFFER_SIZE 32 |
| 19 | char * floatToSane(float x) { |
| 20 | char * end; //This points to the last character of the string |
| 21 | char * i = (char*)malloc(BUFFER_SIZE*sizeof(char)); //The returned string |
| 22 | sprintf(i,"%f",x); //Acquire the "insane" float-printf |
| 23 | end = i + (strlen(i)-1)*sizeof(char); //Calculate the address of the last character |
| 24 | while(*end == '0') { //Destroy all trailing zeroes |
| 25 | *end = '\0'; |
| 26 | end--; |
| 27 | } |
| 28 | if(*end == '.') { //If all zeroes after decimal point -> destroy decimal point |
| 29 | *end = '\0'; |
| 30 | } |
| 31 | |
| 32 | return i; |
| 33 | } |
This is one way of doing it. floatToSane()-functions 2nd line (char * i = ...) is a bit dumb, there has to be a better way.. But I'm tired and really wanna get some sleep.
I hope that helps! Make my function better.
Better to use a static buffer instead of malloc. Or even better, receive the buffer as argument.
Northburns, thanks for that function, I'll use that.
What license is it under? Public domain?
http://www.cppreference.com/stdio/printf.html
It tells you how to pad the field, specify how many characters are displayed and the amount of precision and also specify whether it is right justified (default) or left justified.
I've already seen that page. I tried some of the stuff and it just didn't work.
I'm guessing this is because it's a C++ site.
EDIT:
And I'm using C.
If you look at The index of the cppreference.com site you'll see it is for C and C++.
It works just fine and it is C code. Try again, here's an example.
using_printf_with_floats.c
The output :
c:\ctwoplus\progcode\test>gcc -Wall -o pftest.exe using_printf_with_floats.c c:\ctwoplus\progcode\test>pftest 3.142 3.14 003.1416 c:\ctwoplus\progcode\test>
Northburns, thanks for that function, I'll use that.
What license is it under? Public domain?
License?.. Consider it a gift. So I guess Public domain is pretty accurate. Consider ReyBrujo's suggestions:
Better to use a static buffer instead of malloc. Or even better, receive the buffer as argument.
I'm stunned.
For example I have the numbers 6 and 73.03, I would like printf() to print '6' and '73.03'. Instead of '6.000000' and '73.030000' or '6' and '73', or '6.00' and '73.03'.
Is there a printf() modifier to make this happen or will I have to calculate this myself?
There is: %g.
%g prints the shorter of %e and %f. But if the numbers are not very small or very big or you don't mind the scientific format, then %g is much better option.
Northburns: snprintf!! No one should ever consider coding in C if he doesn't use the nprint functions instead. I guess you don't want your program to turn into a Microsoft product?
Also, better to limit the number of decimal places before you acquire the "insane" text value. That's because floats are never perfectly accurate, so you may want some rounding to happen first.
%g rounds. 7.01 becomes 7 under it.
Edgar, when I get home I'll take a closer look at the options, but I'm fairly sure I tried everything that sounded relevant.
Northburns, thanks for it being public domain!
Fladimir, I converted it to snprintf before I even compiled it. 
EDIT:
That's because floats are never perfectly accurate
I found that, and I rounded it to a maximum of 4 places.
%g prints the shorter of %e and %f.
It will also drop the fractional part if it's all 0 to machine precission (actually, I'm not sure about the tolerance, so take that with a grain of salt).
I don't know if that's a GNU thing or not, but I know it does this (because I use it a lot).
%g rounds. 7.01 becomes 7 under it.
Your C compiler is broken then.
Anyway:
#include <stdio.h> int main(void) { double f1 = 7.; double f2 = 7.01; printf("%g %g\n", f1, f2); return 0; }
produces
7 7.01
%g does exactly what I want.
I didn't expect it to because that cppreference.com site said it does the shorter of %f and %e. Neither of those, AFAICT, does what %g does.
%f prints 6 places, %e prints in standard form.
Anyway, problem solved!