Voltara wrote
I'm working my way through the projects in the second edition of the book, and encountered an inconsistency in how the <tt>gt</tt> and <tt>lt</tt> commands are specified.
<p>
Section 7.3, page 133: "There is only one data type: a signed 16-bit integer." This suggests <tt>gt</tt> and <tt>lt</tt> should treat the operands as signed.
<p>
Since there is only one data type, all arithmetic operations have to use that data type. The relational operations are arithmetic, so the the operands are signed. The comment regarding specific operations is in the way of a reminder -- it does NOT imply that any operation that doesn't have that reminder is now a data type that doesn't exist.
In <tt>projects/06/pong/Pong.asm</tt> (which I assume is output from the author's VM translator), the GT implementation is unsigned: subtract <tt>x-y</tt> and test the sign of the result.
This makes no sense. What does it mean to test the sign of the result? If the data type is unsigned, then the result is unsigned and is always positive.
For instance, what if x = 50,000 and y = 40,000? Then x-y = 10,000 and the "sign bit" is zero. But what if x = 50,000 and y = 10,000? Now x-y = 40,000 and the "sign bit" will be one. Yet in both cases x>y is true.
Testing if x>y by testing if (x-y) > 0 works for both positive and negative values of x and y provided you don't get into overflow conditions. Overflow conditions create caveats for a lot of functions and N2T does have a tendency to ignore them in the interest of keeping the implementations clean and simple. You can argue whether or not this is a reasonable compromise.
The VM program in <tt>projects/07/StackArithmetic/StackTest/StackTest.vm</tt> only tests cases where both operands are positive, so it doesn't help to disambiguate.
No test suite is going to be able to test everything, but there are a number of test suites in the projects that fail to test major cases. I'm hoping that these will get an overhaul when (and if) the new tools come out.
One example where signed and unsigned implementations will give different results is the comparison <tt>32767 > -1</tt> (the difference <tt>32767 - (-1)</tt> rolls over to <tt>-32768</tt>.)
This is an example of the overflow issue I mentioned above.
Keep in mind that ANY operation that uses or results in -32768 is an oddball case because this is the "troublesome" value in 16-bit two's comp. But your point is valid and can be demonstrated with other values that don't involve the pathological one.
A correct signed implementation would handle the separate cases of same sign bit (subtract and test the sign of the result) and opposite sign bit (the negative operand is always lesser.)
This is definitely a better implementation, but it does add quite a bit of additional overhead doing the sign tests.
Also note that it still misbehaves for the pathological case.
Is 0 > -32768?
Is -32768 > 0?
You get the same answer for both since -(-32768) = -32768.