[net.lang.c] Non-zero lower bounds

kpmartin@watmath.UUCP (Kevin Martin) (08/26/84)

With non-zero lower bounds, but no bounds checking, there is no need for
subtracting each lower subscript bound from the corresponding subscript.
Since the lower bounds and multipliers are constants, all the constant
terms can be pulled out, to form one constant, e.g. for a zero-origin
10 by 20 by 30 array,
  z_offset(i, j, k) = 20 * (30 * i + j) + k
For one-origin,
  general_offset(i, j, k) = 20 * (30 * (i-1) + (j-1)) + (k-1)
                          = 20 * (30 * i - 30 + j - 1) + (k-1)
                          = 20 * (30 * i + j - 31) + (k-1)
                          = 20 * (30 * i + j) - 620 + k - 1
                          = 20 * (30 * i + j) + k - 621
                          = z_offset(i, j, k) - z_offset(1, 1, 1)

Note that the second term is a compile-time constant.
                    Kevin Martin, UofW Software Development Group

rbt@sftig.UUCP (08/28/84)

>>With non-zero lower bounds, but no bounds checking, there is no need for
>>subtracting each lower subscript bound from the corresponding subscript.
>>Since the lower bounds and multipliers are constants, all the constant
>>terms can be pulled out, to form one constant, e.g. for a zero-origin
>>10 by 20 by 30 array,
>>  z_offset(i, j, k) = 20 * (30 * i + j) + k
>>For one-origin,
>>  general_offset(i, j, k) = 20 * (30 * (i-1) + (j-1)) + (k-1)
>>                          = 20 * (30 * i - 30 + j - 1) + (k-1)
>>                          = 20 * (30 * i + j - 31) + (k-1)
>>                          = 20 * (30 * i + j) - 620 + k - 1
>>                          = 20 * (30 * i + j) + k - 621
>>                          = z_offset(i, j, k) - z_offset(1, 1, 1)
>>
>>Note that the second term is a compile-time constant.
>>                    Kevin Martin, UofW Software Development Group
>>

The Fortran compiler for the UNIVAC 1108 used to do exactly this sort of thing
all the time.  They went one step further and added the constant offset into
the starting address of the array at compile time and placed that address into
the address part of the memory reference instruction and the z_offset value
into an index register.  This resulted in very fast subscript calculation and
a very subtle bug.  

Sometimes the starting address of the array was a small number, and the
constant offset was a large number, so the number that the compiler wanted to
put into the address field of the instruction turned out to be negative.  This
would not have been a problem, except that the hardware insisted on treating
its address fields as unsigned numbers.  When this happened,  it usually
resulted in a storage limits violation, which was easy to debug, but sometimes
it did not (especially for very large programs, which occupied most of the
address space -- a random storage reference had a high probability of
succeeding) and then the program ran but produced wrong answers.  The poor
user had the devil's own time  finding that sort of bug!  Worse yet, there
was not very much the user could do to work around it once they *had* found
the problem.

Rick Thomas
ihnp4!btlunix!rbt