home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 247_01 / bnmuldv.any < prev    next >
Text File  |  1989-04-19  |  12KB  |  378 lines

  1. /*
  2.  *  MIRACL routine muldiv
  3.  *  bnmuldv.c
  4.  * 
  5.  *  calculates (a*b+c)/m and (a*b+c)%m as quickly as
  6.  *  possible. Should ideally be written in assembly
  7.  *  language of target machine for speed and/or to allow
  8.  *  largest possible MAXBASE. See mirdef.h. The problem is
  9.  *  to avoid overflow in the calculation of the intermediate
  10.  *  product a*b+c. Note that this routine needs only work
  11.  *  for UNSIGNED parameters 
  12.  *
  13.  *  First are shown two straight-forward portable approaches, 
  14.  *  which needs a long data type capable of holding
  15.  *  the product of two int types (i.e. twice as long).
  16.  *  The second method uses the 'ldiv' function which
  17.  *  is defined in the new ANSI standard for C. If you are
  18.  *  using a C compiler which complies with this standard, this
  19.  *  should be faster, as it calculates quotient and remainder
  20.  *  simultaneously (somebody up there heard me!).
  21.  *
  22.  *  This is followed by various other assembly language
  23.  *  implementations for popular processors, computers and 
  24.  *  compilers.
  25.  *
  26.  *  Since parameter passing and returning is time-consuming,
  27.  *  this routine should be generated 'inline', if compiler
  28.  *  allows it.
  29.  *
  30.  
  31. int muldiv(a,b,c,m,rp)
  32. int a,b,c,m,*rp;
  33. {
  34.     long p;
  35.     int q;
  36.     p=(long)a*b+c;
  37.     q=p/m;
  38.     *rp=p-(long)q*m;
  39.     return q;
  40. }
  41.  
  42. #include <stdlib.h>
  43.  
  44. int muldiv(a,b,c,m,rp)
  45. int a,b,c,m,*rp;
  46. {
  47.     ldiv_t r;
  48.     r=ldiv((long)a*b+c,(long)m);
  49.     *rp=(int)r.rem;
  50.     return (int)r.quot;
  51. }
  52.  
  53. ;
  54. ;   VAX11 version for Dec C compiler
  55. ;   with 32 bit int using 64-bit quadword
  56. ;   for the intermediate product. 
  57. ;
  58.     .entry muldiv,0
  59.     subl   #4,sp
  60.     emul   4(ap),8(ap),12(ap),r0   ;a*b+c
  61.     ediv   16(ap),r0,r0,@20(ap)    ;quo. in r0, rem. in *rp
  62.     ret
  63.     .end
  64.  
  65. ;
  66. ;  IBM-PC versions - small memory model only
  67. ;  Easily modified for other memory models
  68. ;
  69. ;  Microsoft C compiler V4.0+
  70. ;  Written for MS macro-assembler
  71. ;
  72.         ASSUME CS:_TEXT
  73. _TEXT   SEGMENT BYTE PUBLIC 'CODE'
  74.  
  75.         PUBLIC _muldiv
  76. _muldiv PROC NEAR
  77.         push bp                 ;standard C linkage
  78.         mov  bp,sp
  79.  
  80.         mov  ax,[bp+4]          ;get a
  81.         mul  WORD PTR [bp+6]    ;multiply by b
  82.         add  ax,[bp+8]          ;add c to low word
  83.         adc  dx,0h              ;add carry to high word
  84.         div  WORD PTR [bp+10]   ;divide by m
  85.         mov  bx,[bp+12]         ;get address for remainder
  86.         mov  [bx],dx            ;store remainder
  87.  
  88.         pop  bp                 ;standard C return
  89.         ret                     ;quotient in ax
  90.  
  91. _muldiv endP
  92.  
  93. _TEXT   ENDS
  94. END
  95.  
  96. /*
  97.  *  Turbo C compiler V1.0. Uses inline assembly feature
  98.  *  Generates code identical to above Microsoft version
  99.  */
  100. int muldiv(a,b,c,m,rp)
  101. int a,b,c,m,*rp;
  102. {
  103.     asm mov  ax,a             ;/* get a                     */
  104.     asm mul  WORD PTR b       ;/* multiply by b             */
  105.     asm add  ax,c             ;/* add c to low word         */
  106.     asm adc  dx,0h            ;/* add carry to high word    */
  107.     asm div  WORD PTR m       ;/* divide by m               */
  108.     asm mov  bx,rp            ;/* get address for remainder */
  109.     asm mov  [bx],dx          ;/* store remainder           */
  110.     return (_AX);
  111. }
  112. /*    Replace last two asm lines when using large data memory models */
  113. /*    asm les  bx, DWORD PTR rp          ; get address for remainder */
  114. /*    asm mov  WORD PTR es:[bx],dx       ; store remainder           */
  115.  
  116. ;
  117. ;  Zorland C compiler Version 1.1 (Lattice C compatible)
  118. ;  Note that later versions of Zortech C (and C++) use the MS version
  119. ;  Written for MS macro-assembler
  120. PGROUP  GROUP PROG
  121. PROG    SEGMENT BYTE PUBLIC 'PROG'
  122.         ASSUME CS:PGROUP
  123.         PUBLIC muldiv
  124. muldiv  PROC NEAR
  125.         push bp                 ;standard C linkage
  126.         mov  bp,sp
  127.  
  128.         mov  ax,[bp+4]          ;get a
  129.         mul  WORD PTR [bp+6]    ;multiply by b
  130.         add  ax,[bp+8]          ;add c to low word
  131.         adc  dx,0h              ;add carry to high word
  132.         div  WORD PTR [bp+10]   ;divide by m
  133.         mov  bx,[bp+12]         ;get address for remainder
  134.         mov  [bx],dx            ;store remainder
  135.  
  136.         pop  bp                 ;standard C return
  137.         ret                     ;quotient in ax
  138.  
  139. muldiv  endP
  140.  
  141. PROG    ENDS
  142. END
  143.  
  144. ;
  145. ;   Aztec C compiler V3.4
  146. ;
  147. CODESEG SEGMENT BYTE PUBLIC 'CODESEG'
  148.         ASSUME CS:CODESEG
  149.         PUBLIC muldiv_
  150. muldiv_ PROC NEAR
  151.         push bp                 ;standard C linkage
  152.         mov  bp,sp
  153.  
  154.         mov  ax,[bp+4]          ;get a
  155.         mul  WORD PTR [bp+6]    ;multiply by b
  156.         add  ax,[bp+8]          ;add c to low word
  157.         adc  dx,0h              ;add carry to high word
  158.         div  WORD PTR [bp+10]   ;divide by m
  159.         mov  bx,[bp+12]         ;get address for remainder
  160.         mov  [bx],dx            ;store remainder
  161.  
  162.         pop  bp                 ;standard C return
  163.         ret                     ;quotient in ax
  164.  
  165. muldiv_ endP
  166.  
  167. CODESEG ENDS
  168. END
  169.  
  170. /
  171. /  Mark Williams C compiler V2.0
  172. /
  173. .globl muldiv_
  174.  
  175. muldiv_:
  176.         push bp                 /standard C linkage
  177.         mov  bp,sp
  178.  
  179.         mov  ax,4(bp)           /get a
  180.         mul  6(bp)              /multiply by b
  181.         add  ax,8(bp)           /add c to low word
  182.         adc  dx,$0x00           /add carry to high word
  183.         div  10(bp)             /divide by m
  184.         mov  bx,12(bp)          /get address for remainder
  185.         mov  (bx),dx            /store remainder
  186.  
  187.         pop  bp                 /standard C return
  188.         ret                     /quotient in ax
  189.  
  190. ;
  191. ;  IBM-PC-8087 for Microsoft C compiler V4.0+
  192. ;  with 'small' defined as 'long' (32 bit). See mirdef.h
  193. ;  This allows IBM-PC to look like 32-bit computer
  194. ;  (which it isn't). To make use of this option:
  195. ;
  196. ;  (1) Must have 8087 Maths Co-processor (for speed and to hold 64-bit
  197. ;      intermediate product).
  198. ;
  199. ;  (2) Must use 'ANSI' enhanced type C compiler, e.g. Microsoft V3.0+
  200. ;      and must use header 'miracl.h' which declares function
  201. ;      parameter types. Changes will be necessary in 'mirdef.h'
  202. ;
  203. ;      Note: many compilation warnings may be generated - ignore them.  
  204. ;
  205. ;  Note: This is NOT, in most cases, faster, but it does allow
  206. ;        very high precision calculations, e.g. 1000!
  207. ;
  208.         ASSUME CS:_TEXT
  209. _TEXT   SEGMENT BYTE PUBLIC 'CODE'
  210.  
  211.         PUBLIC _MULDIV
  212. _muldiv PROC NEAR
  213.         push si                 ;standard C linkage
  214.         push bp          
  215.         mov  bp,sp
  216.  
  217.         finit                   ;initialise 8087
  218.         fild  DWORD PTR [bp+6]  ;get a
  219.         fimul DWORD PTR [bp+0ah];multiply by b
  220.         fiadd DWORD PTR [bp+0eh];add c
  221.         fild  DWORD PTR [bp+12h];get m
  222.         fld st(1)               ;duplicate a*b+c on stack
  223.         fprem                   ;get remainder
  224.         fist  DWORD PTR [bp+0ah];store remainder in b
  225.         fsubr st,st(2)          ;subtract rem from total
  226.         fdiv st,st(1)           ;divide by m
  227.         fist  DWORD PTR [bp+6]  ;store quotient in a
  228.         wait
  229.  
  230.         mov  si,[bp+22]         ;get address for remainder
  231.         mov  ax,[bp+10]
  232.         mov  dx,[bp+12]         ;get remainder
  233.         mov  [si],ax
  234.         mov  [si+2],dx          ;store remainder
  235.         mov  ax,[bp+6]
  236.         mov  dx,[bp+8]          ;get quotient in dx:ax
  237.  
  238.         pop  bp                 ;standard C return
  239.         pop  si
  240.         ret
  241.  
  242. _muldiv endP
  243.  
  244. _TEXT   ENDS
  245. END
  246.  
  247. ;
  248. ;  IBM-80386 version - for Microsoft C V5.0+
  249. ;  Written for MS macro-assembler V5.0+ by Andrej Sauer 
  250. ;  Same comments apply as above (except for 8087 requirement)   
  251. ;
  252.         .386
  253.         ASSUME CS:_TEXT
  254. _TEXT   SEGMENT USE16 PUBLIC 'CODE'
  255.  
  256.         PUBLIC _MULDIV
  257. _muldiv PROC  NEAR
  258.         push  bp                     ;standard C linkage
  259.         mov   ebp,esp
  260.  
  261.         mov   eax,[ebp+4]            ;get a
  262.         mul   DWORD PTR [ebp+8]      ;multiply by b
  263.         add   eax,DWORD PTR [ebp+12] ;add c to low word
  264.         adc   edx,0h                 ;add carry to high word
  265.         div   DWORD PTR [ebp+16]     ;divide by m
  266.         movzx ebx,WORD PTR [ebp+20]  ;get address for remainder, zero high
  267.         mov   [ebx],edx              ;store remainder
  268.         shld  edx,eax,16             ;shift higher half of quotient
  269.                                      ;into lower half of edx
  270.  
  271.         pop   bp                     ;standard C return
  272.         ret                          ;quotient: high bits in dx, lows in ax
  273.  
  274. _muldiv endP
  275.  
  276. _TEXT   ENDS
  277. END
  278.  
  279. int muldiv(a,b,c,m,rp)
  280. int a,b,c,m,*rp;
  281. {
  282.     asm
  283.     {
  284.     ;
  285.     ;  MACintosh version for Megamax C compiler
  286.     ;  with 16-bit int, 68000 processor
  287.     ;
  288.         move   a(A6),D1      ;get a
  289.         mulu   b(A6),D1      ;multiply by b
  290.         move   c(A6),D0      ;get c
  291.         ext.l  D0            ;extend to longword
  292.         add.l  D0,D1         ;D1 contains a*b+c
  293.         divu   m(A6),D1      ;divide by m
  294.         move   D1,D0         ;return with quotient in D0
  295.         swap   D1            ;get remainder
  296.         move.l rp(A6),A0     ;get address for remainder
  297.         move   D1,(A0)       ;store remainder
  298.     }
  299. }
  300.  
  301. int muldiv(a,b,c,m,rp)
  302. int a,b,c,m,*rp;
  303. {
  304.     asm
  305.     {
  306.     ;
  307.     ; 32016 processor version for BBC Master Scientific
  308.     ; with 32-bit int, by Dudley Long, Rutherford-Appleton Labs.
  309.     ;
  310.         movd   a,0           ;move a to R0
  311.         meid   b,0           ;multiply  by b, result extended
  312.         addd   c,0           ;add c to extended number in R0 & R1
  313.         addcd  #0,1
  314.         deid   m,0           ;divide by m
  315.         movd   0,0(rp)       ;remainder to *rp
  316.         movd   1,0           ;quotient returned in R0
  317.     }
  318. }
  319.  
  320. ;
  321. ; Acorn ARM Risc version (32-bit) for Archimedes micro
  322. ; unsigned only
  323. ; Wingpass Macro Assembler
  324. ;
  325. .INCLUDE "A.REGNAMES"
  326.  
  327. .AREA C$$code, .CODE, .READONLY
  328.  
  329. muldiv::
  330.          MOV     ip, sp             ;standard linkage
  331.          STMFD   sp!, {v1-v4}
  332.  
  333.          CMPS    a2,#0x40000000     ;check for b=MAXBASE
  334.          MOVEQ   v3,a1,LSL #30      ;this idea is quicker because
  335.          MOVEQ   v4,a1,LSR #2       ;of ARM barrel shifting capability
  336.          BEQ     addin
  337.          MOV     v1,a1,LSR #16      ;do it the hard way
  338.          MOV     v2,a2,LSR #16
  339.          BIC     a1,a1,v1,LSL #16
  340.          BIC     a2,a2,v2,LSL #16
  341.          MUL     v3,a1,a2           ;form partial products of a*b
  342.          MUL     v4,v1,v2
  343.          SUB     v1,v1,a1
  344.          SUB     v2,a2,v2
  345.          MLA     v1,v2,v1,v3        ;look - only 3 MULs!
  346.          ADD     v1,v1,v4
  347.          ADDS    v3,v3,v1,LSL #16
  348.          ADC     v4,v4,v1,LSR #16
  349. addin:
  350.          ADDS    v3,v3,a3           ;now add in c
  351.          ADCCS   v4,v4,#0
  352.  
  353.          CMPS    a4,#0x40000000     ;check for m=MAXBASE
  354.          MOVEQ   a1,v3,LSR #30
  355.          ADDEQ   a1,a1,v4,LSL #2
  356.          BICEQ   v4,v3,#0xC0000000
  357.          BEQ     leave
  358.          MOV     a1,#0              ;do long division by m
  359.  
  360. divlp:
  361.  
  362. .REPEAT 32                          ;2xfaster than a loop!
  363.          MOVS    v3,v3,ASL #1       ;get next bit into carry
  364.          ADC     v4,v4,v4           ;accumulate remainder
  365.          CMPS    v4,a4
  366.          SUBCS   v4,v4,a4
  367.          ADC     a1,a1,a1           ;accumulate quotient
  368. .ENDREPEAT
  369.  
  370. leave:
  371.          LDR     v3,[ip]
  372.          STR     v4,[v3]       ;store remainder
  373.          LDMFD   sp!, {v1-v4}
  374.          MOVS pc,lr
  375. */
  376.  
  377.