0

I am currently working through Nand2tetris for an university course and it's mostly straightforward. But the alu can do subtraction in a single step and I absolutely do not understand how this works.

opMinus = addition <> notX <> notOut

I couldn't find any explanation for this online. And the last step when trying to derive this myself looks like nonsense even though quickcheck says it is correct:

a - b
a + !b + 1 -- 2s complement
!!(a + !b + 1) -- double negation
!(!a + b) -- apparently this is correct and i have no clue why

The last step feels like it relies on something like

!(a+b) == !a + !b + 1

but I have no intuition why this works so an explanation would be very much appreciated. Thanks for reading!

Taren
  • 674
  • 5
  • 11

3 Answers3

1

One way to look at it more intuitively instead of just algebraically is considering the action bitwise complement has on the entire number line, which is to flip it around symmetrically. !a + b then adds b in that flipped-around context, and the final ! flips everything back around. Stepping one unit "forward" (so, b = 1) in the flipped context takes one step backwards in the normal context, and so forth.

That kind of "flip, action, flip" effectively turns the action in the middle around from the direction it normally works in, there are other instances of the principle, sometimes with both arguments flipped for example min(a, b) = !max(!a, !b).

harold
  • 61,398
  • 6
  • 86
  • 164
  • I didn't get why it would step forward but looking at `!(a+b)` as `-(a+b)-1` makes it kinda obvious in retrospect. – Taren Apr 20 '19 at 11:13
1

I didn't see a good explanation for people with less understanding of this, so I'll do my best to explain what the book for the projects tells you.

Since a few cpus actually have chips that take a signal to switch adders into subtractors (a better way to say this would actually be that they have their transistors arranged in a way to allow for this) and nand2tetris doesn't, you actually have to negate the number you're subtracting (b). To do this in binary you NOT it. If life were simple, this would be your final step.

Take this for example, however. Say you're programming. You're using a signed 8bit int to hold a value b.

This would mean that !b = -(b). So, if b=127, !b = -(127+1) = -128. To correct for this you add 1 to !b to get the correct value of -127. We're now at the correct number we intended to subtract, so we can move on with adding b to a (the number we want to subtract from). If a = 1, and b = 127, if we do a + !(b) + 1, you would get -126 as a result, since 1 + (-128) + 1 = 2-128 = -126.

Also, note that while I used ! to represent NOT, the actual bitwise operation is ~. This is referred to as 2's compliment and you can read more about that here: https://en.wikipedia.org/wiki/Two%27s_complement

Edit: removed an error.

SirGouki
  • 11
  • 1
0

After playing with this some more I figured it out:

(a-b)
!!(a-b)            | double bitwise not is id
!(!(a-b)+1-1)      | +1-1 is id
!(-(a-b)-1)        | !(a-b)+1 = -(a-b)
!(-a + b - 1)      | distribute the negation
!(!a + 1 + b - 1)  | -a = !a+1
!(!a + b)
Taren
  • 674
  • 5
  • 11
  • Yes, so often the process of stating (and writing down) the question is the seed of the answer. Congratulations on figuring it out! – MadOverlord Apr 20 '19 at 11:10