I'm tired of this tom-foolery occurring during runtime , although I'm sure we all are, when our programs screw up at runtime in the most obscure ways.
Getting to the point, the entire source code is a bit large to place here, but still <200 lines, so that's here . Use it if running the program, since the code I will post below is just functions, where I think the error lies.
Context : This is a sort of shift cipher with 8 different shifts taken using an 8 digit pin.
The issue is strange. Basically, the encrypt() function works correctly always -I've matched it by doing the algorithm for myself on paper ; for example, ABC is correctly encoded to 3c 45 46 -6f when the Pin is 12345678.
The strange issues are with the decrypt() function.
When the program is run for the first time, trying to run decrypt() on a valid ciphertext-pin pair always returns nothing except a /n (newline) . When tried with a different valid pin-ciphertext pair, after a successful run of encrypt() is done first, the decrypt() function just returns either the same message which was just encrypted or some other random output from the previously encoded message.
Without further ado, the legendarily screwed up decrypt function which I have rebuilt thrice now -
void decrypt()
{
printf("\n");
int *digits = pin(); int d[8];
getchar();
for (int i=0;i<8;i++)
d[i] = *(digits + i); //puts each digit in a local array.
printf("\nEnter encoded message -\n\n");
getchar();
int j; char ch, msg[3002];
for(int i=0; i < 3000;i++)
{
scanf("%x",&j);
if(j==-111){
msg[i] = '\0'; //terminates string with \0
break;
}
else{
if(ctln(i)==1)
ch = j - d[2];
else if(fib(i)==1)
ch = j + d[4];
else if(luc(i)==1)
ch = j - d[0];
else if(pent(i)==1)
ch = j + d[6];
else if(hex(i)==1)
ch = j - d[3];
else if(prm(i)==1)
ch = j + d[7];
else {
if(i%2 == 0)
ch = j - d[1];
else
ch = j + d[5];
msg[i] = ch;
}
}
}
printf("\nDecrypted message -\n\n");
puts(msg);
}
For context, as well as finding the culprits here, do make sure to read the full code here , with the pin() returning a pointer to a static int array holding all 8 digits , as well as the ctln() , fib(), luc(), pent(), hex(), prm() [ which check if position value i of char in message is a part of Catalan, Fibonacci , Lucas, Pentagon, Hexagon, Prime number series. More here.
Edit 1
I have already tried keeping different variable names, and some other things I can't fully recall. Also, because it is very relevant, below is the pin() function:
int *pin()
{
int num,q=0; static int pins[8];
printf("Enter 8-digit PIN : ");
scanf("%d", &num);
for(register int i = 10000000 ; i >= 1 ; i = (i/10)) // i is position of digit.
{
int d = ((num - (num % i)) / i); // d stores 'digit' ( divides quotient of (num % i) by i)
pins[q] = d; q++;
num = (num - ( d * i ));
}
return pins ; // pointer to static array storing digits of PIN
}
Edit 2
I had wrongly assigned pins[6] rather than pins[8] in the original code, I have corrected it but am still facing the same errors.
Edit 3
After correcting the mistake pointed out by MikeCAT, it now ignores the first character when deciphering.
Edit 4
The getchar() before scanf() was to blame, removing it fixes the last issue too. Thanks #MikeCAT !
In your decrypt() function, msg[i] = ch; is executed only if none of the functions ctln, fib, luc, pent, hex, prm returned 1.
Therefore, uninitialized value of non-static local variable msg, which is indeterminate, may be used for printing and undefined behavior may be invoked.
The part
msg[i] = ch;
}
should be
}
msg[i] = ch;
as it is done in encrypt() function.
I got a char array, a huge array char p[n] read from a txt like.
//1.txt
194.919 -241.808 234.896
195.569 -246.179 234.482
194.919 -241.808 234.896
...
foo(char *p, float x, float y, float z)
{
}
I tried to use atof, strtod, but they are real time consuming when the array is too huge, because they will call the strlen(). and the sscanf is also very slow....
I debug into the code and find that both atof() and strtod call the strlen() in the visual studio, we can check the crt code.
strtod() call:
answer = _fltin2( &answerstruct, ptr, (int)strlen(ptr), 0, 0, _loc_update.GetLocaleT());
atof() call:
return( *(double *)&(_fltin2( &fltstruct, nptr, (int)strlen(nptr), 0, 0, _loc_update.GetLocaleT())->dval) );
I also try to use strtok, but we should not change any data in the 1.txt.
so any one have the best way to convert all these to float x, y, z.
Visual studio 2008 + WIN7
If you can make additional assumptions about the format of the floating point values, parsing them yourself might increase performance.
Example code for parsing ' ' or '\n'-separated values without exponents and no input validation:
float parsef(const char **str)
{
const char *cc = *str;
_Bool neg = (*cc == '-');
if(neg) ++cc;
float value = 0, e = 1;
for(; *cc != '.'; ++cc)
{
if(*cc == ' ' || *cc == '\n' || !*cc)
{
*str = cc;
return neg ? -value : value;
}
value *= 10;
value += *cc - '0';
}
for(++cc;; ++cc)
{
if(*cc == ' ' || *cc == '\n' || !*cc)
{
*str = cc;
return neg ? -value : value;
}
e /= 10;
value += (*cc - '0') * e;
}
}
Example code:
const char *str = "42 -15.4\n23.001";
do printf("%f\n", parsef(&str));
while(*str++);
Okay, how about doing the tokenization yourself and then calling strtod.
What I'm thinking is something like this:
char *current = ...; // initialited to the head of your character array
while (*current != '\0')
{
char buffer[64];
unsigned int idx = 0;
// copy over current number
while (*current != '\0' && !isspace(*current))
{
buffer[idx++] = *current++;
}
buffer[idx] = '\0';
// move forward to next number
while (*current != '\0' && isspace(*current))
{
current++;
}
// use strtod to convert buffer
}
Some issues with this is the tokenization is very simple. It will work for the format you posted, but if the format varies (another line uses : to separate the numbers), it won't work.
Another issue is that the code assumes all numbers have < 64 characters. If they are longer, you'll get a buffer overflow.
Also, the copying to a temporary buffer will add some overhead (but hopefully less then the overhead of constantly doing a strlen on the entire buffer). I know you said you can't change the original buffer, but can you do a temporary change (i.e. the buffer can change as as long as you return it to it's original state before you return):
char *current = ...; // initialited to the head of your character array
while (*current != '\0')
{
char *next_sep = current;
while (*next_sep != '\0' && !isspace(*next_sep))
{
next_sep++;
}
// save the separator before overwriting it
char tmp = *next_sep;
*next_sep = '\0';
// use strtod on current
// Restore the separator.
*next_sep = tmp;
current = next_sep;
// move forward to next number
while (*current != '\0' && isspace(*current))
{
current++;
}
}
This technique means no copying and no worries about buffer overflow. You do need to temporarily modify the buffer; hopefully that is
Check out this code.
It can be further optimized if there's no need to support scientific representation, '+' sign, or leading tabs.
It doesn't use strlen, or any other standard library string routine.
// convert floating-point value in string represention to it's numerical value
// return false if NaN
// F is float/double
// T is char or wchar_t
// '1234.567' -> 1234.567
template <class F, class T> inline bool StrToDouble(const T* pczSrc, F& f)
{
f= 0;
if (!pczSrc)
return false;
while ((32 == *pczSrc) || (9 == *pczSrc))
pczSrc++;
bool bNegative= (_T('-') == *pczSrc);
if ( (_T('-') == *pczSrc) || (_T('+') == *pczSrc) )
pczSrc++;
if ( (*pczSrc < _T('0')) || (*pczSrc > _T('9')) )
return false;
// todo: return false if number of digits is too large
while ( (*pczSrc >= _T('0')) && (*pczSrc<=_T('9')) )
{
f= f*10. + (*pczSrc-_T('0'));
pczSrc++;
}
if (_T('.') == *pczSrc)
{
pczSrc++;
double e= 0.;
double g= 1.;
while ( (*pczSrc >= _T('0')) && (*pczSrc<=_T('9')) )
{
e= e*10. + (*pczSrc-_T('0'));
g= g*10. ;
pczSrc++;
}
f+= e/g;
}
if ( (_T('e') == *pczSrc) || (_T('E') == *pczSrc) ) // exponent, such in 7.32e-2
{
pczSrc++;
bool bNegativeExp= (_T('-') == *pczSrc);
if ( (_T('-') == *pczSrc) || (_T('+') == *pczSrc) )
pczSrc++;
int nExp= 0;
while ( (*pczSrc >= _T('0')) && (*pczSrc <= _T('9')) )
{
nExp= nExp*10 + (*pczSrc-_T('0'));
pczSrc++;
}
if (bNegativeExp)
nExp= -nExp;
// todo: return false if exponent / number of digits of exponent is too large
f*= pow(10., nExp);
}
if (bNegative)
f= -f;
return true;
}
As long as you are not using a particularly bad standard library (impossible these times, they are all good) it's not possible to do it faster than atof.
I don't see any reason why strod() should call strlen(). Of course it might, but nothing in its specification requires it and I'd be suprised if it did. And I'd say that strtod() about as fast as you'll get, short of writing some FPU processor-specific stuff yourself.
Why do you think atof, strtod use strlen? I've never implemented them, but I can't imagine why they'd need to know the length of the input string. It would be of no value to them. I'd use strtod as per Jason's answer. That's what it's for.
And yes, if you have a very large amount of text, it's going to take some time to convert. That's just the way it is.
Use strtod. It almost certainly does not call strlen. Why would it need to know the length of the input? It merely runs past leading whitespace, then consumes as many characters as possible that make sense for a floating point literal, and then returns a pointer just past that. You can see an example implementation Perhaps you're using it non-optimally? Here's a sample of how to use strtod:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *p = "1.txt 194.919 -241.808 234.896 195.569 -246.179 234.482 194.919 -241.808 234.896";
char *end = p;
char *q;
double d;
while(*end++ != ' '); // move past "1.txt"
do {
q = end;
d = strtod(q, &end);
printf("%g\n", d);
} while(*end != '\0');
}
This outputs:
194.919
-241.808
234.896
195.569
-246.179
234.482
194.919
-241.808
234.896
on my machine.
As others have said, I don't think you're going to do much better than the standard library calls. They have been around for a long time and are quite highly optimized (well, they should be, at least in good implementations).
That said, there are some things that aren't clear to me. Are you reading the whole file into memory and then converting the array to another array? If so, you might want to check that the system you are running on has enough memory to do that with swapping. If you are doing this, would it be possible to just convert one line at a time as you read them off disk instead of storing them?
You could consider multithreading your program. One thread to read and buffer lines off disk, and n threads to process the lines. Dr. Dobb's Journal published a great single-reader/single-writer lockless queue implementation you could use. I've used this in a similar app. My worker threads each have an input queue, and then reader thread reads data off disk and places them into these queues in round robin style.
How about something like:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static float frac[] =
{
0.000,
0.001,
0.002,
... // fill in
0.997,
0.998,
0.999,
};
static float exp[] =
{
1e-38,
1e-37,
1e-36,
... // fill in
1e+36,
1e+37,
1e+38,
};
float cvt(char* p)
{
char* d = strchr(p, '.'); // Find the decimal point.
char* e = strchr(p, 'e'); // Find the exponent.
if (e == NULL)
e = strchr(p, 'E');
float num = atoi(p);
if (num > 0) {
num += frac[atoi(d + 1)];
} else {
num -= frac[atoi(d + 1)];
}
if (e)
num *= exp[atoi(e)];
return num;
}
int main()
{
char line[100];
while(gets(line)) {
printf("in %s, out %g\n", line, cvt(line));
}
}
Should be good to three significant digits.
Edit: watch out for big mantissas.
Edit again: and negative exponents. :-(
I doubt if strlen is costing you much.
If you can take advantage of your numbers falling in a relatively restricted range, then what I suggest is to parse it yourself, doing as little computation as possible, such as:
#define DIGIT(c) ((c)>='0' && (c)<='9')
BOOL parseNum(char* *p0, float *f){
char* p = *p0;
int n = 0, frac = 1;
BOOL bNeg = FALSE;
while(*p == ' ') p++;
if (*p == '-'){p++; bNeg = TRUE;}
if (!(DIGIT(*p) || *p=='.')) return FALSE;
while(DIGIT(*p)){
n = n * 10 + (*p++ - '0');
}
if (*p == '.'){
p++;
while(DIGIT(*p)){
n = n * 10 + (*p++ - '0');
frac *= 10;
}
}
*f = (float)n/(float)frac;
if (bNeg) *f = -*f;
*p0 = p;
return TRUE;
}
I keep stumbling on the format specifiers for the printf() family of functions. What I want is to be able to print a double (or float) with a maximum given number of digits after the decimal point. If I use:
printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);
I get
359.013
359.010
Instead of the desired
359.013
359.01
Can anybody help me?
This can't be done with the normal printf format specifiers. The closest you could get would be:
printf("%.6g", 359.013); // 359.013
printf("%.6g", 359.01); // 359.01
but the ".6" is the total numeric width so
printf("%.6g", 3.01357); // 3.01357
breaks it.
What you can do is to sprintf("%.20g") the number to a string buffer then manipulate the string to only have N characters past the decimal point.
Assuming your number is in the variable num, the following function will remove all but the first N decimals, then strip off the trailing zeros (and decimal point if they were all zeros).
char str[50];
sprintf (str,"%.20g",num); // Make the number.
morphNumericString (str, 3);
: :
void morphNumericString (char *s, int n) {
char *p;
int count;
p = strchr (s,'.'); // Find decimal point, if any.
if (p != NULL) {
count = n; // Adjust for more or less decimals.
while (count >= 0) { // Maximum decimals allowed.
count--;
if (*p == '\0') // If there's less than desired.
break;
p++; // Next character.
}
*p-- = '\0'; // Truncate string.
while (*p == '0') // Remove trailing zeros.
*p-- = '\0';
if (*p == '.') { // If all decimals were zeros, remove ".".
*p = '\0';
}
}
}
If you're not happy with the truncation aspect (which would turn 0.12399 into 0.123 rather than rounding it to 0.124), you can actually use the rounding facilities already provided by printf. You just need to analyse the number before-hand to dynamically create the widths, then use those to turn the number into a string:
#include <stdio.h>
void nDecimals (char *s, double d, int n) {
int sz; double d2;
// Allow for negative.
d2 = (d >= 0) ? d : -d;
sz = (d >= 0) ? 0 : 1;
// Add one for each whole digit (0.xx special case).
if (d2 < 1) sz++;
while (d2 >= 1) { d2 /= 10.0; sz++; }
// Adjust for decimal point and fractionals.
sz += 1 + n;
// Create format string then use it.
sprintf (s, "%*.*f", sz, n, d);
}
int main (void) {
char str[50];
double num[] = { 40, 359.01335, -359.00999,
359.01, 3.01357, 0.111111111, 1.1223344 };
for (int i = 0; i < sizeof(num)/sizeof(*num); i++) {
nDecimals (str, num[i], 3);
printf ("%30.20f -> %s\n", num[i], str);
}
return 0;
}
The whole point of nDecimals() in this case is to correctly work out the field widths, then format the number using a format string based on that. The test harness main() shows this in action:
40.00000000000000000000 -> 40.000
359.01335000000000263753 -> 359.013
-359.00999000000001615263 -> -359.010
359.00999999999999090505 -> 359.010
3.01357000000000008200 -> 3.014
0.11111111099999999852 -> 0.111
1.12233439999999995429 -> 1.122
Once you have the correctly rounded value, you can once again pass that to morphNumericString() to remove trailing zeros by simply changing:
nDecimals (str, num[i], 3);
into:
nDecimals (str, num[i], 3);
morphNumericString (str, 3);
(or calling morphNumericString at the end of nDecimals but, in that case, I'd probably just combine the two into one function), and you end up with:
40.00000000000000000000 -> 40
359.01335000000000263753 -> 359.013
-359.00999000000001615263 -> -359.01
359.00999999999999090505 -> 359.01
3.01357000000000008200 -> 3.014
0.11111111099999999852 -> 0.111
1.12233439999999995429 -> 1.122
To get rid of the trailing zeros, you should use the "%g" format:
float num = 1.33;
printf("%g", num); //output: 1.33
After the question was clarified a bit, that suppressing zeros is not the only thing that was asked, but limiting the output to three decimal places was required as well. I think that can't be done with sprintf format strings alone. As Pax Diablo pointed out, string manipulation would be required.
I like the answer of R. slightly tweaked:
float f = 1234.56789;
printf("%d.%.0f", f, 1000*(f-(int)f));
'1000' determines the precision.
Power to the 0.5 rounding.
EDIT
Ok, this answer was edited a few times and I lost track what I was thinking a few years back (and originally it did not fill all the criteria). So here is a new version (that fills all criteria and handles negative numbers correctly):
double f = 1234.05678900;
char s[100];
int decimals = 10;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf("10 decimals: %d%s\n", (int)f, s+1);
And the test cases:
#import <stdio.h>
#import <stdlib.h>
#import <math.h>
int main(void){
double f = 1234.05678900;
char s[100];
int decimals;
decimals = 10;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf("10 decimals: %d%s\n", (int)f, s+1);
decimals = 3;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf(" 3 decimals: %d%s\n", (int)f, s+1);
f = -f;
decimals = 10;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf(" negative 10: %d%s\n", (int)f, s+1);
decimals = 3;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf(" negative 3: %d%s\n", (int)f, s+1);
decimals = 2;
f = 1.012;
sprintf(s,"%.*g", decimals, ((int)(pow(10, decimals)*(fabs(f) - abs((int)f)) +0.5))/pow(10,decimals));
printf(" additional : %d%s\n", (int)f, s+1);
return 0;
}
And the output of the tests:
10 decimals: 1234.056789
3 decimals: 1234.057
negative 10: -1234.056789
negative 3: -1234.057
additional : 1.01
Now, all criteria are met:
maximum number of decimals behind the zero is fixed
trailing zeros are removed
it does it mathematically right (right?)
works (now) also when first decimal is zero
Unfortunately this answer is a two-liner as sprintf does not return the string.
Why not just do this?
double f = 359.01335;
printf("%g", round(f * 1000.0) / 1000.0);
I search the string (starting rightmost) for the first character in the range 1 to 9 (ASCII value 49-57) then null (set to 0) each char right of it - see below:
void stripTrailingZeros(void) {
//This finds the index of the rightmost ASCII char[1-9] in array
//All elements to the left of this are nulled (=0)
int i = 20;
unsigned char char1 = 0; //initialised to ensure entry to condition below
while ((char1 > 57) || (char1 < 49)) {
i--;
char1 = sprintfBuffer[i];
}
//null chars left of i
for (int j = i; j < 20; j++) {
sprintfBuffer[i] = 0;
}
}
What about something like this (might have rounding errors and negative-value issues that need debugging, left as an exercise for the reader):
printf("%.0d%.4g\n", (int)f/10, f-((int)f-(int)f%10));
It's slightly programmatic but at least it doesn't make you do any string manipulation.
Some of the highly voted solutions suggest the %g conversion specifier of printf. This is wrong because there are cases where %g will produce scientific notation. Other solutions use math to print the desired number of decimal digits.
I think the easiest solution is to use sprintf with the %f conversion specifier and to manually remove trailing zeros and possibly a decimal point from the result. Here's a C99 solution:
#include <stdio.h>
#include <stdlib.h>
char*
format_double(double d) {
int size = snprintf(NULL, 0, "%.3f", d);
char *str = malloc(size + 1);
snprintf(str, size + 1, "%.3f", d);
for (int i = size - 1, end = size; i >= 0; i--) {
if (str[i] == '0') {
if (end == i + 1) {
end = i;
}
}
else if (str[i] == '.') {
if (end == i + 1) {
end = i;
}
str[end] = '\0';
break;
}
}
return str;
}
Note that the characters used for digits and the decimal separator depend on the current locale. The code above assumes a C or US English locale.
A simple solution but it gets the job done, assigns a known length and precision and avoids the chance of going exponential format (which is a risk when you use %g):
// Since we are only interested in 3 decimal places, this function
// can avoid any potential miniscule floating point differences
// which can return false when using "=="
int DoubleEquals(double i, double j)
{
return (fabs(i - j) < 0.000001);
}
void PrintMaxThreeDecimal(double d)
{
if (DoubleEquals(d, floor(d)))
printf("%.0f", d);
else if (DoubleEquals(d * 10, floor(d * 10)))
printf("%.1f", d);
else if (DoubleEquals(d * 100, floor(d* 100)))
printf("%.2f", d);
else
printf("%.3f", d);
}
Add or remove "elses" if you want a max of 2 decimals; 4 decimals; etc.
For example if you wanted 2 decimals:
void PrintMaxTwoDecimal(double d)
{
if (DoubleEquals(d, floor(d)))
printf("%.0f", d);
else if (DoubleEquals(d * 10, floor(d * 10)))
printf("%.1f", d);
else
printf("%.2f", d);
}
If you want to specify the minimum width to keep fields aligned, increment as necessary, for example:
void PrintAlignedMaxThreeDecimal(double d)
{
if (DoubleEquals(d, floor(d)))
printf("%7.0f", d);
else if (DoubleEquals(d * 10, floor(d * 10)))
printf("%9.1f", d);
else if (DoubleEquals(d * 100, floor(d* 100)))
printf("%10.2f", d);
else
printf("%11.3f", d);
}
You could also convert that to a function where you pass the desired width of the field:
void PrintAlignedWidthMaxThreeDecimal(int w, double d)
{
if (DoubleEquals(d, floor(d)))
printf("%*.0f", w-4, d);
else if (DoubleEquals(d * 10, floor(d * 10)))
printf("%*.1f", w-2, d);
else if (DoubleEquals(d * 100, floor(d* 100)))
printf("%*.2f", w-1, d);
else
printf("%*.3f", w, d);
}
I found problems in some of the solutions posted. I put this together based on answers above. It seems to work for me.
int doubleEquals(double i, double j) {
return (fabs(i - j) < 0.000001);
}
void printTruncatedDouble(double dd, int max_len) {
char str[50];
int match = 0;
for ( int ii = 0; ii < max_len; ii++ ) {
if (doubleEquals(dd * pow(10,ii), floor(dd * pow(10,ii)))) {
sprintf (str,"%f", round(dd*pow(10,ii))/pow(10,ii));
match = 1;
break;
}
}
if ( match != 1 ) {
sprintf (str,"%f", round(dd*pow(10,max_len))/pow(10,max_len));
}
char *pp;
int count;
pp = strchr (str,'.');
if (pp != NULL) {
count = max_len;
while (count >= 0) {
count--;
if (*pp == '\0')
break;
pp++;
}
*pp-- = '\0';
while (*pp == '0')
*pp-- = '\0';
if (*pp == '.') {
*pp = '\0';
}
}
printf ("%s\n", str);
}
int main(int argc, char **argv)
{
printTruncatedDouble( -1.999, 2 ); // prints -2
printTruncatedDouble( -1.006, 2 ); // prints -1.01
printTruncatedDouble( -1.005, 2 ); // prints -1
printf("\n");
printTruncatedDouble( 1.005, 2 ); // prints 1 (should be 1.01?)
printTruncatedDouble( 1.006, 2 ); // prints 1.01
printTruncatedDouble( 1.999, 2 ); // prints 2
printf("\n");
printTruncatedDouble( -1.999, 3 ); // prints -1.999
printTruncatedDouble( -1.001, 3 ); // prints -1.001
printTruncatedDouble( -1.0005, 3 ); // prints -1.001 (shound be -1?)
printTruncatedDouble( -1.0004, 3 ); // prints -1
printf("\n");
printTruncatedDouble( 1.0004, 3 ); // prints 1
printTruncatedDouble( 1.0005, 3 ); // prints 1.001
printTruncatedDouble( 1.001, 3 ); // prints 1.001
printTruncatedDouble( 1.999, 3 ); // prints 1.999
printf("\n");
exit(0);
}
Here is my first try at an answer:
void
xprintfloat(char *format, float f)
{
char s[50];
char *p;
sprintf(s, format, f);
for(p=s; *p; ++p)
if('.' == *p) {
while(*++p);
while('0'==*--p) *p = '\0';
}
printf("%s", s);
}
Known bugs: Possible buffer overflow depending on format. If "." is present for other reason than %f wrong result might happen.
Slight variation on above:
Eliminates period for case (10000.0).
Breaks after first period is processed.
Code here:
void EliminateTrailingFloatZeros(char *iValue)
{
char *p = 0;
for(p=iValue; *p; ++p) {
if('.' == *p) {
while(*++p);
while('0'==*--p) *p = '\0';
if(*p == '.') *p = '\0';
break;
}
}
}
It still has potential for overflow, so be careful ;P
I would say you should use
printf("%.8g",value);
If you use "%.6g" you will not get desired output for some numbers like.32.230210 it should print 32.23021 but it prints 32.2302
Hit the same issue, double precision is 15 decimal, and float precision is 6 decimal, so I wrote to 2 functions for them separately
#include <stdio.h>
#include <math.h>
#include <string>
#include <string.h>
std::string doublecompactstring(double d)
{
char buf[128] = {0};
if (isnan(d))
return "NAN";
sprintf(buf, "%.15f", d);
// try to remove the trailing zeros
size_t ccLen = strlen(buf);
for(int i=(int)(ccLen -1);i>=0;i--)
{
if (buf[i] == '0')
buf[i] = '\0';
else
break;
}
return buf;
}
std::string floatcompactstring(float d)
{
char buf[128] = {0};
if (isnan(d))
return "NAN";
sprintf(buf, "%.6f", d);
// try to remove the trailing zeros
size_t ccLen = strlen(buf);
for(int i=(int)(ccLen -1);i>=0;i--)
{
if (buf[i] == '0')
buf[i] = '\0';
else
break;
}
return buf;
}
int main(int argc, const char* argv[])
{
double a = 0.000000000000001;
float b = 0.000001f;
printf("a: %s\n", doublecompactstring(a).c_str());
printf("b: %s\n", floatcompactstring(b).c_str());
return 0;
}
output is
a: 0.000000000000001
b: 0.000001
I needed that and the first answer from paxdiablo does the trick. But I was not needing truncating and the version below is maybe slightly faster?
Starting to search end of string (EOS) after the ".", only one placement of EOS.
//https://stackoverflow.com/questions/277772/avoid-trailing-zeroes-in-printf
//adapted from paxdiablo (removed truncating)
char StringForDouble[50];
char *PointerInString;
void PrintDouble (double number) {
sprintf(StringForDouble,"%.10f",number); // convert number to string
PointerInString=strchr(&StringForDouble[0],'.'); // find decimal point, if any
if(PointerInString!=NULL) {
PointerInString=strchr(&PointerInString[0],'\0'); // find end of string
do{
PointerInString--;
} while(PointerInString[0]=='0'); // remove trailing zeros
if (PointerInString[0]=='.') { // if all decimals were zeros, remove "."
PointerInString[0]='\0';
} else {
PointerInString[1]='\0'; //otherwise put EOS after the first non zero char
}
}
printf("%s",&StringForDouble[0]);
}
My idea is to calculate the required precision that would not result in trailing zeroes for a given double value and pass it to the "%1.*f" format in printf().
This can even be done as one-liner:
int main() {
double r=1234.56789;
int precision=3;
printf(L"%1.*f", prec(r, precision), r);
}
int prec(const double& r, int precision)
{
double rPos = (r < 0)? -r : r;
double nkd = fmod(rPos, 1.0); // 0..0.99999999
int i, ex10 = 1;
for (i = 0; i < precision; ++i)
ex10 *= 10;
int nki = (int)(nkd * ex10 + 0.5);
// "Eliminate" trailing zeroes
int requiredPrecision = precision;
for (; requiredPrecision && !(nki % 10); ) {
--requiredPrecision;
nki /= 10;
}
return requiredPrecision;
}
And here is another %g solution. You should always provide a format precision that is "wide enough" (default is only 6) and round the value. I think this is a nice way to do it:
double round(const double &value, const double& rounding) {
return rounding!=0 ? floor(value/rounding + 0.5)*rounding : value;
}
printf("%.12g" round(val, 0.001)); // prints up to 3 relevant digits
Your code rounds to three decimal places due to the ".3" before the f
printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);
Thus if you the second line rounded to two decimal places, you should change it to this:
printf("%1.3f", 359.01335);
printf("%1.2f", 359.00999);
That code will output your desired results:
359.013
359.01
*Note this is assuming you already have it printing on separate lines, if not then the following will prevent it from printing on the same line:
printf("%1.3f\n", 359.01335);
printf("%1.2f\n", 359.00999);
The Following program source code was my test for this answer
#include <cstdio>
int main()
{
printf("%1.3f\n", 359.01335);
printf("%1.2f\n", 359.00999);
while (true){}
return 0;
}