Search code examples
cbinarycomplement

How to check whether a number is binary or 2's complement in C?


I was making a binary adder in C using only logic gates. Now for example, I wanted to add 4 + (-5) so I would get the answer in 2's complement and then convert it to decimal. In the same way, if I do, 4 + (-3) I would get the answer in binary and would like to use the same function to convert it to decimal.

Now, I know how to convert a 2's complement number into decimal, convert binary into decimal. But I want to use the same function to convert both 2's complement and binary into decimal. To do that, I have to figure out if the number is binary or 2's complement. It is where I am stuck.

Can someone give me an idea, algorithm or code in C to find out whether a number is 2's complement or normal binary?

SOURCE CODE

Chips

// Author: Ashish Ahuja
// Date created: 8-1-2016
// Descriptions: This file stores all the chips for
//               the nand2tetris project.
// Links: www.nand2tetris.org
//        class.coursera.org/nand2tetris1-001
// Files needed to compile successfully: ourhdr.h

int not (unsigned int a) {
    if (a == 1) {
          return 0;
    }
    else if (a == 0) {
          return 1;
    }
}

int and (unsigned int a, unsigned int b) {
    if (a == 1 && b == 1)
          return 1;
    else if ((a == 1 && b == 0) || (a == 0 && b == 1) || (a == 0 && b == 0))
          return 0;
}

int nand (unsigned int a, unsigned int b) {
    unsigned int ans = 10;
    ans = and (a, b);
    unsigned int ack = not (ans);
    return ack;
}

int or (unsigned int a, unsigned int b) {
    return (nand (not (a), not (b)));
}

int nor (unsigned int a, unsigned int b) {
    return (not (or (a, b)));
}

int xor (unsigned int a, unsigned int b) {
    unsigned int a_r;
    unsigned int b_r;
    unsigned int sra;
    unsigned int srb;
    a_r = not (a);
    b_r = not (b);
    sra = nand (a_r, b);
    srb = nand (b_r, a);
    return nand (sra, srb);
}

int xnor (unsigned int a, unsigned int b) {
    return (not (xor (a,b)));
}

Ourhdr.h

include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#include <termios.h>
#include <stddef.h>
#include <sys/types.h>
#include <my/signal.h>
#include <my/socket.h>
#include <my/io.h>
#include <my/lib.h>
#include <my/tree.h>
#include <my/bits.h>
#include <my/binary.h>
//#include <my/error.h>

#define MAXLINE 4096
#define BUFF_SIZE 1024

Note: I am gonna only show headers needed by this project. So just think that the other headers are of no use.

Function to Convert array to integer

int array_num (int arr [], int n) {
    char str [6] [2];
    int i;
    char number [13] = {'\n'};
    for (i = 0; i < n; i ++)
        sprintf (str [i], "%d", arr [i]);
    for (i = 0; i < n; i ++)
        strcat (number, str [i]);
    i = atoi (number);
    return i;
}

Function to get bits of an int, and return an pointer to an array containing bits

int *get_bits (int n, int bitswanted) {
    int *bits = malloc (sizeof (int) * bitswanted);
    int k;
    int mask;
    int masked_n;
    int thebit;
    for (k = 0; k < bitswanted; k ++) {
        mask = 1 << k;
        masked_n = n & mask;
        thebit = masked_n >> k;
        bits [k] = thebit;
    }
    return bits;
}

Function to convert binary to decimal, and vice-versa

int convert_num (int n, int what) {
    int rem;
    int i;
    int binary = 0;
    int decimal = 0;

    switch (what) {
        case 0:                    // Convert decimal to binary
             i = 0;
             rem = 0;
             while (n != 0) {
                   rem = n % 2;
                   n /= 2;
                   binary += rem * i;
                   i *= 10;
             }
             return binary;
             break;
        case 1:                   // Convert binary to decimal
             i = 0;
             rem = 0;
             while (n != 0) {
                   rem = n % 10;
                   n /= 10;
                   decimal += rem*pow (2, i);
                   i ++;
             }
             return decimal;
             break;
    }
}

Main program design

  • Read two numbers n1 and n2 from user
  • Get an pointer bits1 and bits2 which point to an array which have the bits of n1 and n2. Note, that the array will be in reverse order, i.e, the last bit will be in the 0th variable of the array.
  • Put a for loop in which you will pass three variables, i.e, the bits you want to add and carry from the last adding of bits operation.
  • The return value will be the the addition of the three bits and carry, will be changed to the carry after the addition (if any). Eg- You pass 1 and 0, and carry is 1, so, the return will be 0 and carry will be again changed to 1.
  • The return will be stored in another array called sum.
  • The array sum will be converted to an int using the function I have given above.
  • Now this is where I am stuck. I now want to change the int into a decimal number. But to do that, I must know whether, it is in form of a 2's compliment number, or just a normal binary. I do not know how to do that.

NOTE: The nand2tetris project is done in hdl but I was familiar to do it with C. Also, many of the function I have mentioned above have been taken from stackoverflow. Although, the design is my own.


Solution

  • Fun fact about 2s complement - and reason it has become so widely used is:

    For addition you don't need to know if it is negative or positive. Just add as unsigned.

    Subtraction is similar, but you have to negate the second operand (see below).

    The only thing you might have to care about is overflow. For that you have to check if the sign of the result can actually result from the signs of the two inputs and a addition-overflow from the pre-most to the most signigficant bit.

    Negation of int n is simply done by 0 - n. Alternatively, you can invert all bits and add 1 - that's what a CPU or hardware subtracter basically does.

    Note that 2's complement binaries have an asymmetric range: -(N+1) ... N.

    For conversion, just check for the minimum value (must be treated seperately) and output directly, otherwise get the sign (if ( n < 0 )) and negate the value (n = -n) and finally convert the -then unsigned/positive - value to a string or character stream.