Skip to navigation

BBC Micro Elite

Adding sign-magnitude numbers

Doing basic arithmetic with sign-magnitude numbers

References: ADD
  Elite uses a lot of sign-magnitude numbers, where the sign bit is stored
  separately from an unsigned magnitude. The classic examples are the ship
  coordinates at INWK, which are stored in 24 bits as as (x_sign x_hi x_lo),
  where bit 7 of x_sign is the sign, and (x_hi x_lo) is the coordinate value.
  
  This means that when we come to do arithmetic on sign-magnitude numbers, we
  have to write our own routines for everything from addition and subtraction
  to multiplication and division, as the standard two's complement maths that
  the 6502 supports won't work.
  
  For example, let's try adding 127 and -1 as sign-magnitude numbers, first
  using sign-magnitude arithmetic. 127 is 01111111 as a sign-magnitude number,
  while -1  is 10000001, and:
  
    127 + -1 = 0 1111111 + 1 0000001
             = 0 1111111 - 0 0000001
             = 0 1111110
             = 126
  
  However, if we use the built-in ADC instruction, we get the following:
  
    127 + -1 = 01111111 + 10000001
             = 00000000
  
  which is a completely different result.
  
  Elite's ADD routine implements sign-magnitude addition using the following
  algorithm. We want to add A and S, so:
  
    * If both A and S are positive, just add them as normal
  
    * If both A and S are negative, then add them and make sure the result is
      negative
  
    * If A and S have different signs, then we can use the absolute values of A
      and S to work out the sum, as follows:
  
      * Subtract the smaller absolute value from the larger absolute value
  
      * Give the answer the same sign as the argument with the larger absolute
        value
  
  To see why this works, try visualising a number line containing the two
  numbers A and S, with one to the left of zero and one to the right. Adding
  the numbers is a bit like moving the number with the larger absolute value
  towards zero on the number line, moving it by the amount of the smaller
  absolute number; so it's like subtracting the smaller absolute value from the
  larger one. You can also see that the sum of the two numbers will be on the
  same side of zero as the number that is furthest from zero, so that's why the
  answer should have the same sign as the argument with the larger absolute
  value.
  
  We can implement these steps like this:
  
    * If |A| = |S|, then the result is 0
  
    * If |A| > |S|, then the result is |A| - |S|, with the sign set to the same
      sign as A
  
    * If |S| > |A|, then the result is |S| - |A|, with the sign set to the same
      sign as S
  
  So that's what we do in the ADD routine to implement 16-bit sign-magnitude
  addition. The same basic approach can be found in lots of Elite's arithmetic
  routines: check the signs of the two operands, then add, subtract, divide or
  multiply as appropriate, and finally set the sign bit correctly.