Live data from Hacker News

Two's complement – You beauty

everyogi.in

21–30 of 92 posts

Re: Two's complement – You beauty

#21
post #14

It's an elegant construct, but this used to be a part of an entry-level course in every computer school I know of. Have things changed now?

US universities with ABET-accredited programs teach 1's/2's complement to freshman EE/CpE majors in a first course on digital logic, which typical doesn't have any prerequisites.

Re: Two's complement – You beauty

#22
post #6

This all is suddenly less surprising for people who learned some modulo arithmetics in school (or university). That is, calculating with the remainders of division. For example: - Calculating "modulo 60" means calculating time with a round clock in mind, considering only minutes and ignoring hours (and seconds). - Calculating with angles (in degrees) means just calculating "modulo 360". - "modulo 1000" means calculat…

I didn't downvote you. However, I am a math person and your post feels wrong for some reason. It isn't wrong, but it feels like it should be; and I am not entirely sure why.

CPUs use modular arithmetic for both signed (two's complement) and unsigned values, so that cannot be the defining feature of twos complement. The insight with two's complement is that we can interperet the "upper" half of numbers as negative. As you say, this should be very familar to anyone who has worked with modular arithmatic. For those who have not, this just means that (in 3-bit twos complement/ integers mod 8). We interperate 7 = 8-1 = -1 and so on. As a result of this, operations on signed and unsigned integers are literally identical. Almost.

CPUs differ from modular arithmetic in 1 way: multiplication. Specifically, CPUs do not do modular arithmetic for multiplication. However, the result of the multiplication of two n-bit numbers could be as big as 2n-bits. When CPUs do this multiplication, they store the result in two registers. If you only look at the bottom register, the result is equivalent to modular arithmatic. However, if you consider the top register, the result is not (this is why there is a MUL and IMUL instruction).

Arguably, the same thing happens for addition. However, because there is at most 1 extra bit needed, it is not given its own register, but rather, the upper digit is stored in the carry flag.

The other insight of two's complement is encoding. Under the construction I presented above, if given the 3-bit twos complement number 0b111, we would have to compute that:

    0b111 > 0b011
    0b111 = 0b1000 - 0b0001
The insight of two complement is a way performing this computation using primitive bitwise operations. Specifically:

   If the first bit is 0, we are done
   Otherwise, perform bitwise negation, add 1, and consider the result "negative". 
There is no obvious equivelent of this method for other bases.

Re: Two's complement – You beauty

#25
post #19
post #9

I program a UNISYS 2200 mainframe at work. It uses 1's complement. Yes, there are two zeros. Not a problem in practice because all arithmetic operations normalize -0 to +0 at no extra cost in execution time, so -0 practially doesn't happen. IIRC from Assembler class, addition is implemented as subtraction of the negative operand. Just in case anyone ever needs it, e.g. for bitmaps, the SZ (store zero) assembler instr…

> What _is_ annoying about the UNISYS boxes is the 36 bit word format, though. Characters are stored in 9 bit quarterwords that map pretty awkwardly to bytes containing 8-bit ASCII. Binary data formats are essentially incompatible with anything. This is why the FTP protocol has a byte size command. If all you have is 8-bit bytes then that seems strange. But at the time FTP was designed the most common machines on the…

The example C function in the article uses 8 instead of CHAR_BIT, which today seems not worth complaining about. I never knew there used to be so many machines with non-8-bit bytes.

Re: Two's complement – You beauty

#26
post #17

Shitty C code: the binary printing function is needlessly complicated. void print_bin(int x){ for(unsigned m=~(~0u>>1); m ; m>>=1) putchar(x&m?'1':'0'); putchar('\n'); }

On the contrary I'd say. When you're talking about low level (and basic CS101 details like 2's complement) I think it makes sense to be lucid rather than "needlessly complicated short" code that does too much in a single line.

Re: Two's complement – You beauty

#27

Would it be possible to use - 0 & +0 in useful ways, like determining "direction" of previous operation? No clue how that could be useful, but I'm betting there's a use case out there.

Yes! Although I'm not sure if it would ever be useful for integers, it's vital in floating point: https://people.freebsd.org/~das/kahan86branch.pdf

Re: Two's complement – You beauty

#28
post #17

Shitty C code: the binary printing function is needlessly complicated. void print_bin(int x){ for(unsigned m=~(~0u>>1); m ; m>>=1) putchar(x&m?'1':'0'); putchar('\n'); }

Shitty C code: I've seen Perl golfs more readable than this.

The article's code is more explicit and verbose, which makes it easier for non-C-programmers (like myself) to actually understand what's going on.

Re: Two's complement – You beauty

#29
post #17

Shitty C code: the binary printing function is needlessly complicated. void print_bin(int x){ for(unsigned m=~(~0u>>1); m ; m>>=1) putchar(x&m?'1':'0'); putchar('\n'); }

Shitty C code: I've seen Perl golfs more readable than this. The article's code is more explicit and verbose, which makes it easier for non-C-programmers (like myself) to actually understand what's going on.

It uses a bit mask from the leftmost bit to the rightmost and prints the respective bits in x. Is that more complicated than allocating memory on the heap, storing the bits, and then printing them in reverse?

Also the code above does not contain anything C specific, with the exception of 'putchar' let's say.

Post reply on HN