FORTRAN 77 on PDP-11

Sean 'Captain Napalm' Conner spc at conman.org
Wed Jul 27 21:16:09 CDT 2005


It was thus said that the Great Jerome H. Fine once stated:
> 
> By the way, are there any standard algorithms for the
> 4 basic operations (add, subtract, multiply and divide)
> for 128 bit numbers which are composed of 8 * 16 bit
> words?  As per your suggestion, I would probably use:
> CHARACTER * 16 ARRAY ( nnn )

  What language?  In assembly addition and subtraction are pretty trivial if
you have a carry bit you can use (not all RISC based CPUs have a carry bit). 
Just make sure you keep track of endian issues (given an array A[n] is A[0]
the Most Significant or Least Significant word?).  

  So, in Intel x86, the addition routine may look like (A[0] = LSW)

multi_byte_add:	mov	ebx,[esp+8]	; source A value
		mov	esi,[esp+12]	; source B value
		mov	edi,[esp+16]	; destination
		mov	ecx,[esp+20]	; size (in 32-bit words)
		clc			; clear carry bit

.mba_loop:	mov	eax,[ebx]
		adc	eax,[esi]
		mov	[edi],eax
		lea	ebx,[ebx+4]
		lea	esi,[esi+4]
		lea	edi,[edi+4]
		dec	ecx
		jnz	.mba_loop

		ret

  Subtraction works simularly.  A full multiplication routine is a bit more
daunting---if you know that you are only going to multiply a big number with
a word, then it's a bit easier, but still, it comes down do how one does
multiplication by hand:

	          A  B  C  D 
	          W  X  Y  Z
	---------------------
	         AZ BZ CZ DZ 
	      AY BY CY DY
	   AX BX CX DX
	AW BW CW DW
	
(and don't forget the carries!)  One trick you might want to try is to take
advantage of the fact that these are binary values so multiplication becomes
shifts and adds but with larger values like these, doing the multibyte
rotates may not be as effective as using the actual MUL instructions.

  Division is nasty, but again, works like long division.

  Doing this stuff in C is possible, but you loose out in speed big time.  A
multibyte addition will look like (warning---untested code! and A[0] = LSW):

#include <limits.h>

void multi_byte_add(unsigned short *s1,unsigned short *s2,unsigned short *dest,size_t size)
{
  int result;
  int carry;

  for (carry = 0 ; size ; size-- , s1++ , s2++ , dest++)
  {
    result = *s1 + *s2 + carry;

    if ((carry = (result > USHRT_MAX))) 
      result -= SHRT_MAX;

    *dest = (unsigned short)result;
  }
}

  I have some C code that does some of this---one is a C implementation of a
techique Woz used in calculating e to 100,000 digits (as described in Byte
magazine of either Dec 1980 or Dec 1981) and another one that does division
in C, if you are interested.

  -spc (Good luck)





More information about the cctalk mailing list