Post by David Higton Post by David Higton Post by Alan Adams
The thing I found surprising is that BASIC displays the values in I% and
J% using a signed interpretation, but does the subtraction in an unsigned
fashion. It's this inconsistency that worries me, in case at some future
date is is "corrected".
It's not inconsistent. This is just how 2's complement addition and
subtraction work. Perhaps you need to work through some more examples.
Doing them on paper, perhaps with a more limited number of bits to make
it less laborious, might help convince you.
It may not be inconsistent if you view it from the viewpoint of
assembler, but it is very much inconsistent from the viewpoint of BASIC
-(very large number) - (another very large number) should never result in
a positive answer.
BASIC shows these values as negative, and returns positive.
That's inconsistent "within the BASIC language scope". It should, to be
consistent, return an underflow error.
You're making an assumption that, in BASIC, integers can only be signed,
and that's what everyone wants. Now I know that BASIC represents them
in PRINT statements as signed, but I don't regard that as the end of the
story. I am well used to thinking about whether I want each one of my
integers to be signed or unsigned. I'm quite happy to use BASIC to
handle unsigned integers. The important thing is that it doesn't fall
over with an error; I'm quite happy to interpret the result of the
calculation myself. (I'm also happy to add a signed integer to an
unsigned integer, etc.)
To my mind and my needs, BASIC does the right thing.
Where it is consistent is that it does the same thing with addition, but
not with multiplication.
That's the same in machine language, AFAIUI. Addition and subtraction
instructions don't need to have signed and unsigned variants, but
multiplication (despite being repeated addition) /does/ require them.
I don't understand why, bearing in mind my comment in brackets, and if
anyone can point me to an explanation, I'd be grateful.
You'll note that in ARM assembly language MUL does not have signed/unsigned
variants. It takes two 32-bit registers, multiplies them, and puts the result
in a 32-bit register, discarding any overflow. That works just as well for
signed and unsigned numbers.
The reason the long multiplication instructions, SMULL and UMULL, have signed
and unsigned versions is that the result has 64 bits despite the operands
each being 32 bits.
In two's complement representation, if you have a negative number like -1
(11111111,11111111,11111111,11111111) then if you want to put the result in
64-bit form you need to extend it to fill the top 32 bits with 1 as well.
Taking things down to a more manageable size, 8 bits and 16 bits:
In 8 bits, 11111111 is -1 (or 255 if unsigned)
11111111 * 2 is 11111110
That's an overflow if the number was unsigned, but it's -2 if signed.
But if you put the result in a 16 bit register, you will get
which is 510, and not -2, unless you have told the processor that you are
doing signed arithmetic, in which case it can make sure that the extra bits
are filled with the appropriate number depending on the sign of the result.
You said about that you're quite happy to interpret the result of the
calculation yourself and that the important thing is that it doesn't fall
over with an error. That's all very well, but there are many applications
where it is better to know about overflows than to ignore them. If you wrote
an accounts package, you might decide to store all the values as integers, in
pennies, to avoid floating point rounding errors. That's fine if you don't
need to deal with any values bigger than £21,474,836.47. But if a business
with a big turnover buys your accounting package, they will get very cross if
you have not guarded against overflow.
It would be an utter pain for anyone writing stuff in BASIC to have to check
each calculation to decide whether an overflow had occurred or not. If BASIC
generated a "Number too big" error for addition and subtraction of integers,
if you want to ignore them, all you need to do is to write a suitable error
The analogy with assembly language is not all that helpful, because you have
access to the flags which make it easy to check whether a calculation has
resulted in an overflow. BASIC's behaviour encourages people to be careless.
Locomotive BASIC on the Amstrad CPC generates on overflow error if you exceed
the 16 bits for integer calculations. This is absolutely necessary because
32768 is not a very bit number for an upper limit. I think Acorn only got
away with it because 32 bits gives pretty big numbers which are adequate for