As a C fresher, I am trying to write a recursive routine to convert a decimal number to the equivalent binary. However, the resultant string is not correct in the output. I think it has to be related to the Type casting from int to char. Not able to find a satisfactory solution. Can anyone help? Thanx in advance.
Code:
#include <stdio.h>
#include <conio.h>
int decimal, counter=0;
char* binary_string = (char*)calloc(65, sizeof(char));
void decimal_to_binary(int);
int main()
{
puts("\nEnter the decimal number : ");
scanf("%d", &decimal);
decimal_to_binary(decimal);
*(binary_string + counter) = '\0';
printf("Counter = %d\n", counter);
puts("The binary equivalent is : ");
puts(binary_string);
return 0;
}
void decimal_to_binary(int number)
{
if (number == 0)
return;
else
{
int temp = number % 2;
decimal_to_binary(number/2);
*(binary_string + counter) = temp;
counter++;
}
}
Should the casting store only the LSB of int in the char array each time?
Do not use global variables if not absolutely necessary. Changing the global variable in the function makes it very not universal.
#include <stdio.h>
char *tobin(char *buff, unsigned num)
{
if(num / 2) buff = tobin(buff, num / 2);
buff[0] = '0' + num % 2;
buff[1] = 0;
return buff + 1;
}
int main(void)
{
char buff[65];
unsigned num = 0xf1;
tobin(buff, num);
printf("%s\n", buff);
}
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int decimal, counter=0;
//char* binary_string = (char*)calloc(65, sizeof(char));
//C does not allow initialization of global variables with
//non constant values. Instead declare a static char array with 65 elements.
//Alternatively declare binary_string in the main function and allocate memory with calloc.
char binary_string[65];
void decimal_to_binary(int);
int main()
{
puts("\nEnter the decimal number : ");
scanf("%d", &decimal);
decimal_to_binary(decimal);
//*(binary_string + counter) = '\0';
// This is more readable:
binary_string[counter] = '\0';
printf("Counter = %d\n", counter);
puts("The binary equivalent is : ");
puts(binary_string);
return 0;
}
void decimal_to_binary(int number)
{
if (number == 0)
return;
else
{
int temp = number % 2;
//decimal_to_binary(number/2);
//you call decimal_to_binary again before increasing counter.
//That means every time you call decimal_to_binary, the value of count
//is 0 and you always write to the first character in the string.
//*(binary_string + counter) = temp;
//This is more readable
//binary_string[counter] = temp;
//But you are still setting the character at position counter to the literal value temp, which is either 0 or 1.
//if its 0, you are effectively writing a \0 (null character) which in C represents the end of a string.
//You want the *character* that represents the value of temp.
//in ASCII, the value for the *character* 0 is 0x30 and for 1 it is 0x31.
binary_string[counter] = 0x30 + temp;
counter++;
//Now after writing to the string and incrementing counter, you can call decimal_to_binary again
decimal_to_binary(number/2);
}
}
If you compile this, run the resulting executable and enter 16 as a number, you may expect to get 10000 as output. But you get00001. Why is that?
You are writing the binary digits to the string in the wrong order.
The first binary digit you calculate is the least significant bit, which you write to the first character in the string etc.
To fix that aswell, you can do:
void decimal_to_binary(int number){
if(number == 0){
return;
}
else{
int temp = number % 2;
counter++;
//Store the position of the current digit
int pos = counter;
//Don't write it to the string yet
decimal_to_binary(number/2);
//Now we know how many characters are needed and we can fill the string
//in reverse order. The first digit (where pos = 1) goes to the last character in the string (counter - pos). The second digit (where pos = 2) goes to the second last character in the string etc.
binary_string[counter - pos] = 0x30 + temp;
}
}
This is not the most efficient way, but it is closest to your original solution.
Also note that this breaks for negative numbers (consider decimal = -1, -1 % 2 = -1).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have a float number in ascii that represents a voltage eg. 5.625V, and I need to remove the decimal point. I do not wish to truncate the number OR loose precision I simply need the number as is without the decimal point.
The resulting number will be inserted into an ascii protocol with a field width of 5 digits in length that represents a voltage and the units is in mV (millivolts) vs V (Volts) as shown in the example above. The number needs to be shown as 5 ascii digits, no decimal notation.
Eg. 5.625V float number in ascii to 5625 mV decimal number in ascii..
Seems simple...but cannot work out an elegant way to do this.
Just convert the number of milliVolts without the fractional part:
char buffer[32];
float voltage = 5.625;
snprintf(buffer, sizeof buffer, "%.0f", voltage * 1000.);
If you want to pad to 5 characters with spaces, and you know the number of milliVolts fits in an int you could use:
snprintf(buffer, sizeof buffer, "%5d", (int)(voltage * 1000));
If you are supposed to pad to 5 characters with leading zeros, use this:
snprintf(buffer, sizeof buffer, "%05d", (int)(voltage * 1000));
If the int on your platform only has 16 bits, you should use a larger type to avoid undefined behavior when converting a float that exceeds INT_MAX. long long is guaranteed to be at least 64 bits. Adjust the printf format specifier accordingly.
Note that conversion to int rounds toward 0 and invokes undefined behavior if the value is out of range for an int. If you know your value is positive and within range, you can get better accuracy with (int)(value * 1000 + 0.5)
The question suggested the input was an ASCII string, so I came up with this:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
long s2mv(const char *s)
{
long mv;
char *end;
int sign;
while (isspace((unsigned char)*s)) {
s++;
}
sign = (*s == '-') ? -1 : 1;
if (*s == '-' || *s == '+') {
s++;
}
mv = 1000 * strtol(s, &end, 10);
s = end;
if (*s++ == '.') {
int place = 100;
while (place && isdigit((unsigned char)*s)) {
mv += place * (*s - '0');
s++;
place /= 10;
}
}
return mv * sign;
}
int main(void)
{
const char *tests[] = {
"0", "12", "-12", "12.", "-12.", "12.345", "-12.345",
"1.234", ".123", "0.123", "-0.123", "-.123"
};
long mv;
int i;
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
mv = s2mv(tests[i]);
printf("s2mv(\"%s\") returned %ld\n", tests[i], mv);
}
return 0;
}
Output:
s2mv("0") returned 0
s2mv("12") returned 12000
s2mv("-12") returned -12000
s2mv("12.") returned 12000
s2mv("-12.") returned -12000
s2mv("12.345") returned 12345
s2mv("-12.345") returned -12345
s2mv("1.234") returned 1234
s2mv(".123") returned 123
s2mv("0.123") returned 123
s2mv("-0.123") returned -123
s2mv("-.123") returned -123
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;
}