home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / arch / 10960 < prev    next >
Encoding:
Internet Message Format  |  1992-11-19  |  7.3 KB

  1. Xref: sparky comp.arch:10960 comp.lang.misc:3814
  2. Newsgroups: comp.arch,comp.lang.misc
  3. Path: sparky!uunet!sun-barr!cs.utexas.edu!uwm.edu!zaphod.mps.ohio-state.edu!sol.ctr.columbia.edu!ira.uka.de!uni-heidelberg!clio!dentzer
  4. From: dentzer@clio.iwr.uni-heidelberg.de (Ralf Dentzer)
  5. Subject: Re: how to advocate new software/hardware features (Re: Hardware Support for Numeric Algorithms)
  6. Message-ID: <1992Nov20.135747.4642@sun0.urz.uni-heidelberg.de>
  7. Sender: news@sun0.urz.uni-heidelberg.de (NetNews)
  8. Organization: IWR, University of Heidelberg, Germany
  9. References: <Bxr8vG.IpI@mentor.cc.purdue.edu> <martin.721995695@bert> <martin.722176263@bert>
  10. Date: Fri, 20 Nov 92 13:57:47 GMT
  11. Lines: 161
  12.  
  13. As some sort of compromise between portability and efficiency I would make
  14. the following proposal for a set of basic functions to deal with multiple
  15. digit integers. The main restriction for them is the imposition to have a 
  16. C-function interface, but only thus portability can be guaranteed.
  17.  
  18. Once the C-interface and a portable C implementation is established you can
  19. feel free to optimize -- use dirty programming tricks or a compiler with
  20. special features or finally use Assembler to exploit all the wonderful
  21. features of your processor.
  22.  
  23. I would highly appreciate an optimized library of these functions
  24. accompaning every C-compiler or development kit I use. As the functions
  25. are very simple and similar to each other this is an easy task for
  26. someone acquainted with the characteristics of the processor and its
  27. assembler language.
  28.  
  29. First there should be a data type "Digit_t" e.g., usually unsigned long
  30. or what else fits into one register, and a constant BitsPerDigit.
  31. Then come six functions for calculating with Digits, these provide
  32. access to carrys, the higher digit of a product and a division
  33. with two digit dividend:
  34.  
  35. Digit_t DigitAdd(Digit_t *sum, Digit_t a, Digit_t b, Digit_t carry);
  36.         /* *sum=LOW-DIGIT(a+b+carry);
  37.        return HIGH-DIGIT(a+b+carry); 
  38.     */
  39. Digit_t DigitSub(Digit_t *diff, Digit_t a, Digit_t b, Digit_t carry);
  40.         /* *diff=RESULT;
  41.        return CARRY;
  42.        where RESULT, CARRY are defined by: 
  43.        2^BitsPerDigit > 
  44.         CARRY*2^BitsPerDigit + a - b - carry == RESULT >= 0
  45.     */
  46. Digit_t DigitMult(Digit_t *prod, Digit_t a, Digit_t b, Digit_t carry);
  47.         /* *prod=LOW-DIGIT(a*b+carry);
  48.        return HIGH-DIGIT(a*b+carry); 
  49.     */
  50. Digit_t DigitMultAdd(Digit_t *res, Digit_t a, Digit_t b, Digit_t carry);
  51.         /* *res=LOW-DIGIT(a*b+carry+*prod);
  52.        return HIGH-DIGIT(a*b+carry+*prod); 
  53.     */
  54. Digit_t DigitMultSub(Digit_t *res, Digit_t a, Digit_t b, Digit_t carry);
  55.         /* *res=RESULT;
  56.        return RESULT;
  57.        where RESULT, CARRY are defined by: 
  58.        2^BitsPerDigit > 
  59.         CARRY*2^BitsPerDigit + *prod - a*b - carry == RESULT >= 0
  60.     */
  61. Digit_t DigitDiv(Digit_t *quot, Digit_t h, Digit_t l, Digit_t d);
  62.     /* Suppose:    d>0 and h<d
  63.        *quot=QUOT;
  64.        return REM;
  65.        where QUOT, REM are defined by: 
  66.        h*2^BitsPerDigit + l == d*QUOT + REM,
  67.        2^BitsPerDigit > REM >= 0
  68.     */
  69.  
  70. These functions are sufficient to build a multiple digit arithmetic,
  71. but due to function call overhead they are too slow.
  72. (More or less, depending on the processor; on a Sparc their
  73. performance is not that bad.)
  74. To get rid of this overhead we have to make an assumption about the
  75. way multiple digit integers are represented. As e.g. Geddes, Czapor and
  76. Labahn pointed out in their book "Algorithms for Computer Algebra"
  77. a representation as a vector (array) of digits is the most efficient
  78. way and should be preferred over e.g. linked lists.
  79.  
  80. So we use the following functions to deal with vectors of l digits.
  81.  
  82. Digit_t DigitVecAdd(Digit_t *sum, Digit_t *a, Digit_t *b, int l)
  83.      /*    sum[0..l-1] = a[0..l-1] + b[0..l-1]; return CARRY;   */
  84.      /* This notation means:
  85.     Add the integers represented by the vectors a and b,
  86.     write the lowest l digits of the result into the vector sum
  87.     and return the carry of this operation.
  88.      */
  89. Digit_t DigitVecSub(Digit_t *diff, Digit_t *a, Digit_t *b, int l)
  90.      /*    diff[0..l-1] = a[0..l-1] - b[0..l-1]; return CARRY;   */
  91.  
  92. I am not sure about having DigitVecAdd or the following function
  93. DigitVecAddCarry or both. DigitVecAdd is simpler but I can imagine
  94. situations where DigitVecAddCarry is more useful.
  95.  
  96. Digit_t
  97. DigitVecAddCarry(Digit_t *sum, Digit_t *a, Digit_t *b, Digit_t carry, int l)
  98.      /*    sum[0..l-1] = a[0..l-1] + b[0..l-1] + carry; return CARRY;   */
  99. Digit_t 
  100. DigitVecSubCarry(Digit_t *diff, Digit_t *a, Digit_t *b, Digit_t carry, int l)
  101.      /*    diff[0..l-1] = a[0..l-1] - b[0..l-1] - carry; return CARRY;   */
  102.  
  103. Digit_t DigitVecMult(Digit_t *res, Digit_t *a, Digit_t m, int l)
  104.      /*    res[0..l-1] = a[0..l-1]*m; return CARRY;   */
  105. Digit_t DigitVecMultAdd(Digit_t *res, Digit_t *a, Digit_t m, int l)
  106.      /*    res[0..l-1] += a[0..l-1]*m; return CARRY;   */
  107.      /* Special function for multiple digit multiplication */
  108. Digit_t DigitVecMultSub(Digit_t *res, Digit_t *a, Digit_t m, int l)
  109.      /*    res[0..l-1] -= a[0..l-1]*m; return CARRY;   */
  110.      /* Special function for multiple digit division */
  111. Digit_t DigitVecDiv(Digit_t *quot, Digit_t *a, Digit_t d, int l)
  112.      /*    quot[0..l-1] = a[0..l-1]/m; 
  113.     return a[0..l-1]%m;
  114.      */
  115.  
  116. Now how would optimized versions of these functions look like?
  117. I can report some of my experiences. First it makes not much difference
  118. to have the additions/subtractions in assembler. On a Mips processor
  119. there is no way of doing it better than with the C commands
  120.     sum = a+b;
  121.     carry = (sum<a);
  122. as these are just two machine instructions.
  123. On a Sparc at least the gcc compiler avoids branches in the above statement
  124. and needs three machine instructions. If you take the overhead for
  125. function call, loads/stores and loop control into account this is
  126. almost as good as possible.
  127.  
  128. Something similar holds for DigitVecDiv, that should just contain
  129. calls to DigitDiv as these calls consume very little time compared
  130. to the actual division. But for DigitDiv itself it is important to
  131. use the best method available.
  132.  
  133. If you just want to substitute the fast machine instructions for
  134. multiplication you should start with the DigitMult* functions, and if
  135. you are willing to do a bit more assembler you can go to DigitVecMult*
  136. now, DigitVecMultAdd being the most important.  Optimizing these
  137. functions also gives you the chance to do instruction scheduling to
  138. get the best out of delay slots or supercsalar execution.
  139.  
  140. Here are a few numbers for multiple precision multiplications of
  141. numbers with 80 decimal digits each on a SparcStation 2 with 
  142. Digit_t == unsigned long, BitsPerDigit == 32:
  143.  
  144. C:                403 (353 using karatsubas trick)
  145. DigitMultAdd in asm:        135
  146. DigitVecMultAdd in asm:        115
  147.  
  148. On a Sparcstation 10-20 with 33 MHz Supersparc processor the best number
  149. achieved was 33. This was a speedup of about 10 compared to the C-version.
  150. But this is due to the usage of the Sparc version 7 multiplication
  151. routine in the C library on the machine I had access to (SunOS 4.1.3) :-)
  152.  
  153. On Mips the corresponding numbers are:
  154.  
  155.                 r3000 (33MHz)    r4000 (50/100 MHz)
  156. C:                173        58
  157. DigitMultAdd in asm:         92        38
  158. DigitVecMultAdd in asm:         50        20
  159.  
  160.  
  161. I would be interested to hear any comments on the functions chosen,
  162. if some are missing (why?), if some are superfluous (why?),
  163. and mainly if they meet people's needs for portability and efficiency.
  164.  
  165.  
  166. Ralf Dentzer
  167. IWR
  168. Universitaet Heidelberg
  169. Im Neuenheimer Feld 368
  170. D-6900 Heidelberg
  171. Germany
  172.  
  173. dentzer@kalliope.iwr.uni-heidelberg.de
  174.