-3

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.

Box Box Box Box
  • 5,094
  • 10
  • 49
  • 67
  • I don't understand. 2's complement is binary. And how do you "make" using logic gates in C? – unwind Jan 13 '16 at 13:36
  • @unwind, you just simulate the logic gates. This is because making circuits needs lots of time and is difficult. – Box Box Box Box Jan 13 '16 at 13:37
  • @unwind, 2's complement is a bit different than binary. I agree it's binary, but it isn't exactly binary. – Box Box Box Box Jan 13 '16 at 13:38
  • 1
    I still don't understand what you mean. And I believe the answer is "no", it's not possible unless you want to add an extra bit that holds this information. – unwind Jan 13 '16 at 13:40
  • It's a quite unclear whether you're talking about binary and 2s complement in C, or whether you're talking about the output of your simulated binary adder, or a mix thereof - and in that case what anyone can do to help. Start with some code rather, and tell us where you got stuck. However, just by looking at a number, a computer can't tell you if it's binary or 2s complement, it's the other way around, you need to tell the computer how to interpret it. – nos Jan 13 '16 at 13:41
  • By *2's complement* vs *binary*, do you mean *signed* vs *unsigned*? – user694733 Jan 13 '16 at 13:41
  • @user694733, I mean signed. – Box Box Box Box Jan 13 '16 at 13:41
  • 1
    Binary is just something fundamental: a raw collection of one's and zeroes. The computer has no idea what those ones and zeroes represent: it could be a signed number or it could be a picture of a cat. It is the job of the programmer to write a program that tells the computer what to do with the binary. It doesn't make sense to go the other way around. You can't have the computer telling you what your program is supposed to do. – Lundin Jan 13 '16 at 13:41
  • @nos, I'll post my code. Just give me a few minutes. – Box Box Box Box Jan 13 '16 at 13:42
  • I'm very interested to get a link to a **current** non-binary computer with more functionality than an Op-Amp. – too honest for this site Jan 13 '16 at 13:43
  • 1
    @AshishAhuja: 2s complement - as any other value in a computer is very well binary. There is no "more or less binary". Todays computers are all binary. Any value representation is just an encoding. For unsigned, there are also other encodings than the simple `2**n` representation. E.g gray-code. – too honest for this site Jan 13 '16 at 13:45
  • @nos. I have posted code and my design. Hope this is enough. If you want anything more, tell me. – Box Box Box Box Jan 13 '16 at 14:24
  • Now it becomes more clear. Note: If you only use boolean values, use the appropriate type. C supports `_Bool` (you can use the more common `boll` if you `#include `). Also it is not necessary to compare with boolean values. You can simply e.g. write `a = !a` for `not`. This works also for normal integer types and is more readable than the explicit comparisons. – too honest for this site Jan 13 '16 at 14:38
  • Correction: It is `bool` of course. – too honest for this site Jan 13 '16 at 14:44
  • A number cannot be binary or 2's complement. Binary is a way of representing a number. 2's complement is a way of representing a number. A number is the number of cars I own, which can be represented in Roman numbers, decimal digits, binary, or any other representation and it will still be the same number. The distinction between numbers and representations is extremely important for programmers to understand. – David Schwartz Feb 21 '16 at 09:22

2 Answers2

4

Both are binary. The difference is signed or unsigned. For >0 this is the same. For <0 you can see that it is a negative number just by looking at the highest bit. Using the same function for output can easily be done by looking at the highest bit, if it is set output '-' and convert the negative two's complement to its abs() which can easily be done bitwise.

CAUTION: If a positive number is big enough to set the highest bit, it can no longer be distinguished from negative two's complement. That is the reason why programming languages do need separate types for this (e.g. in C int and unsigned).

Kellerspeicher
  • 608
  • 4
  • 13
  • There are various other representations which use the MSB as signe, but are not 2's complement. And "a positive number setting ..." is not possible. Because then the encoding does not represent a positive number anymore. An _operation_ OTOH which _would_ change that bit **incorrectly** generates overflow. In C, overflow of signed integers is undefined behaviour - no further research required. – too honest for this site Jan 13 '16 at 13:46
  • Yes. But not relevant for the question here. Otherwise it will be very complicate for an obvious beginner here. – Kellerspeicher Jan 13 '16 at 13:49
  • A beginner starting with such a project as OP has to know about these facts. If he does not understand, he should backup and get the basics right first. Anyway, an answer should be correct and use the correct terms. Notive this will not only be read by OP. To detect if a signed integer is negative, just compare with `0`. No bit-fiddling needed. – too honest for this site Jan 13 '16 at 13:51
  • You are free to provide an educational better adapted answer. The questioner obviously what to fiddle bits: "using only logic gates" – Kellerspeicher Jan 13 '16 at 13:53
0

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.

Community
  • 1
  • 1
too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • What do you mean by _"asymmetric"_? – Box Box Box Box Jan 13 '16 at 14:25
  • Hmm, I have got it. Now I have posted code in the question. Is this enough to make it readable and understandable? Also, I just noticed that you have typed separately wrongly. Can you edit it for future viewers. – Box Box Box Box Jan 13 '16 at 14:33
  • Thanks, edited. Feel free to correct such typos yourself next time. Just a hint: do some research for a "full adder" and "half adder". These are typical logic building blocks of few gates which add two bits and are meant to be cascaded for arbitrary bit-width. Also search for "serial adder". These come from hardware-development. There are also chips available with these functions (74XXyy TTL-logic series). – too honest for this site Jan 13 '16 at 14:39
  • no I couldn't. As the minimum edit limit is 6 characters, and there was nothing else to correct, I only could have contacted you. the author of the post. – Box Box Box Box Jan 13 '16 at 14:43
  • @AshishAhuja: There is a trick: The systems does not notice if you cut/paste the same text ... ;-) – too honest for this site Jan 13 '16 at 14:44
  • that's nice. I'll surely do the edit myself next time. – Box Box Box Box Jan 13 '16 at 15:17
  • I know what a half-adder and a full-adder is. Although, I'll check what a serial adder is. this is all covered in the book - Digital Logic and Computer Design: Morris Mano. This is the book I am using. Although, do you know any internet projects, which are based on hardware circuit simulations, such as this: https://www.coursera.org/course/nand2tetris1 – Box Box Box Box Jan 13 '16 at 15:21
  • @AshishAhuja: I have some homebrew self-built hardware and computers already here from the 70ies and 80ies. I learned that from the diode. So I had my fair amount of burnt fingers from a soldering iron or zaps from self-constructed power supplies. Happy now to use 32 bit MCUs and a good toolchain :-) – too honest for this site Jan 13 '16 at 15:29