0
#include <math.h>
#include <stdio.h>

void main() {
    int decimal, count, binary, digit;
    printf("Enter the number : ");
    scanf("%d", &decimal);
    count = 0; binary = 0;
    while (decimal > 0) {
        digit = decimal % 2;
        binary = binary + digit * pow(10, count);
        decimal = decimal / 2;
        ++count;
    }
    printf("Binary form : %d", binary);
}

I used the above code to convert Decimal to binary. However, the problem is the output.

Input           : 12
Expected Output : 1100
Actual Output   : 1099

[img]https://i.stack.imgur.com/4rMHt.png

This problem persists for other inputs too. Only 8 gives the correct output.

So can someone explain why this happens? This error also shows up in C++, when I port it there.

PS: This error also pops up while using pow in checking if a number is Armstrong and if its a palindrome.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 3
    are you sure ? that's not even possible ... – Mohsen_Fatemi Sep 16 '17 at 18:26
  • 1
    https://repl.it/LLhY/0 I get `1100` – kaza Sep 16 '17 at 18:29
  • You don't want to use `pow` for this sort of thing. Keep a running multiplier, multiplying by `2` or `10` every time. `pow` has inaccuracies. – Steve Summit Sep 16 '17 at 18:30
  • See [is-floating-point-math-broken](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – user3386109 Sep 16 '17 at 18:33
  • 1
    You probably don't want to convert the number into a decimal number that looks like a binary number at all. Binary is just a representation of the same number, so you probably want a string. – M Oehm Sep 16 '17 at 18:33
  • PS integer is not very good to keep this form of the "binary". for 64bit integer the max number is 524287 for 32 bit 1023 – 0___________ Sep 16 '17 at 18:50

3 Answers3

5

The problem comes from the limited precision of the double arithmetic. pow(10, count) may be computed as exp(log(10) * count), which can produce a value that is very close but different from the actual integer result. If this value is smaller than the mathematical value, converting to int does not round to closest, it takes the integral part that will be the previous integer, hence 99 instead of 100.

You should instead use integer arithmetics:

#include <stdio.h>

int main(void) {
    int decimal, binary, digit, pow10;
    printf("Enter the number : ");
    if (scanf("%d", &decimal) == 1) {
        binary = 0;
        pow10 = 1;
        while (decimal > 0) {
            digit = decimal % 2;
            decimal /= 2;
            binary = binary + digit * pow10;
            pow10 *= 10;
        }
        printf("Binary form: %d\n", binary);
    }
    return 0;
}

Note that there are some other issues in your code:

  • The prototype for main without arguments is int main(void).
  • You should print a newline at the end of your output.
  • You should test the return value of scanf().
  • Your method is intrinsically limited to integer values below 2047 (with 32-bit int).

Here is an improved version:

#include <limits.h>
#include <stdio.h>

int main(void) {
    unsigned long long decimal;
    printf("Enter the number: ");
    if (scanf("%llu", &decimal) == 1) {
        char binary[sizeof(decimal) * CHAR_BIT + 1];
        char *p = binary + sizeof(binary);
        *--p = '\0';
        while (decimal > 1) {
            *--p = '0' + (decimal & 1); // '0' or '1' for all encodings
            decimal >>= 1;
        }
        *--p = '0' + decimal;
        printf("Binary form: %s\n", binary);
    }
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Note that pow doesn't have to be implemented in that way, although it's very likely it is - particularly with IEEE754. – Bathsheba Sep 16 '17 at 18:40
  • I would say "limited to integer values 1023 and below". With greater values, `pow10 *= 10;` overflows. – chux - Reinstate Monica Sep 16 '17 at 19:09
  • @chux: good point: my implementation has this problem, but the OP's method could go up to 2047 if `pow(10, count)` behaved correctly. – chqrlie Sep 16 '17 at 19:13
  • Now this is heading towards canonicity, it might be worth mentioning that `'0' + decimal` will work with any encoding supported by C. – Bathsheba Sep 16 '17 at 19:31
  • @Bathsheba: done. `"01"[decimal & 1]` would work too, without the assumption `'1' == '0' + 1`, but the assumption is OK for all encodings and this alternative is less efficient. – chqrlie Sep 16 '17 at 19:43
3

pow(x, y) is most likely implemented as exp(y * log(x)) which can go off for surprisingly small integral arguments. This manifests itself in a particularly pathological way if the result is truncated to an integer.

The moral of the story is to avoid the pow function when working in integer arithmetic.

In your case maintaining a running coefficient with successive multiplications by 10 would be appropriate. Just be careful you don't overflow your int type; the upper limit could be as small as 32767.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • I would suggest avoiding mixing floats & integers. PS using of the `pow` function in such a simple code is a sign of the extreme laziness. – 0___________ Sep 16 '17 at 18:42
1

I think your first problem is your types - you seem to want to build an integer representation of a binary number, and you're also using pow, which has a signature of:

double pow(double x, double y)

So you're adding a double float to an integer. Are you sure you want to do that?

You're probably better off doing the divide by/mod by base loop and building a string and printing that. That's answered here https://math.stackexchange.com/questions/111150/changing-a-number-between-arbitrary-bases

Also, big or little endianness may bite you but is that in the scope of your homework question?

cthon
  • 111
  • 4