dmodeop.red 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. module dmodeop; % Generic operators for domain arithmetic.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1991 The RAND Corporation. All rights reserved.
  4. % internal dividef;
  5. fluid '(!*noequiv); % !*convert
  6. % switch convert;
  7. % !*convert := t;
  8. symbolic procedure !:difference(u,v);
  9. if null u then !:minus v else if null v then u
  10. else if u=v then nil
  11. else if atom u and atom v then u-v
  12. else dcombine(u,v,'difference);
  13. symbolic procedure !:divide(u,v);
  14. % Returns a dotted pair of quotient and remainder of non-invertable
  15. % domain element U divided by non-invertable domain element V.
  16. % Note that a zero is returned as NIL.
  17. if null u then nil . nil
  18. else if null v then rerror(poly,202,"zero divisor")
  19. else if atom u and atom v then dividef(u,v)
  20. else dcombine(u,v,'divide);
  21. symbolic procedure dividef(m,n);
  22. ((if car x=0 then nil else car x) . if cdr x=0 then nil else cdr x)
  23. where x=divide(m,n);
  24. symbolic procedure !:expt(u,n);
  25. % Raises domain element U to integer power N. Value is a domain
  26. % element.
  27. if null u then if n=0 then rerror(poly,11,"0/0 formed") else nil
  28. else if n=0 then 1
  29. else if n=1 then u
  30. else if u=1 then 1
  31. else if n<0
  32. then !:recip !:expt(if not fieldp u then mkratnum u else u,-n)
  33. else if atom u then u**n
  34. % Moved into the exponentiation method of !:mod!:
  35. % else if car u eq '!:mod!:
  36. % then (lambda x; if x=0 then nil else if x=1 then 1 else car u . x)
  37. % general!-modular!-expt(cdr u,n)
  38. else begin scalar v,w,x;
  39. if x := get(car u,'expt)
  40. then return apply2(x,u,n);
  41. % There was a special exponentiation method.
  42. v := apply1(get(car u,'i2d),1); % unit element.
  43. x := get(car u,'times);
  44. a: w := n;
  45. if w-2*(n := n/2) neq 0 then v := apply2(x,u,v);
  46. if n=0 then return v;
  47. u := apply2(x,u,u);
  48. go to a
  49. end;
  50. symbolic procedure !:gcd(u,v);
  51. if null u then v else if null v then u
  52. else if atom u and atom v then gcdn(u,v)
  53. else if fieldp u or fieldp v then 1
  54. else dcombine(u,v,'gcd);
  55. % symbolic procedure !:i2d u;
  56. symbolic procedure !:minus u;
  57. % U is a domain element. Value is -U.
  58. if null u then nil
  59. else if atom u then -u
  60. else (if x then apply1(x,u) else dcombine(u,-1,'times))
  61. where x=get(car u,'minus);
  62. symbolic procedure !:minusp u;
  63. if atom u then minusp u else apply1(get(car u,'minusp),u);
  64. symbolic procedure !:onep u;
  65. if atom u then onep u else apply1(get(car u,'onep),u);
  66. symbolic procedure !:plus(u,v);
  67. if null u then v else if null v then u
  68. else if atom u and atom v
  69. then (if w=0 then nil else w) where w=u+v
  70. else dcombine(u,v,'plus);
  71. % symbolic procedure !:prep u;
  72. % symbolic procedure !:print u;
  73. symbolic procedure !:quotient(u,v);
  74. if null u or u=0 then nil
  75. else if null v or v=0 then rerror(poly,12,"Zero divisor")
  76. else if atom u and atom v
  77. % We might also check that remainder is zero in integer case.
  78. then if null dmode!* then u/v else
  79. (if atom recipv then u*recipv else dcombine(u,recipv,'times))
  80. where recipv=!:recip v
  81. else dcombine(u,v,'quotient);
  82. symbolic procedure !:recip u;
  83. % U is an invertable domain element. Value is 1/U.
  84. begin
  85. if numberp u
  86. then if abs u=1 then return u
  87. else if null dmode!* or dmode!* memq '(!:rd!: !:cr!:)
  88. then return !:rn2rd mkrn(1,u)
  89. else u := apply1(get(dmode!*,'i2d),u);
  90. return (if not atom x and car x='!:rn!: then !:rn2rd x else x)
  91. where x=dcombine(1,u,'quotient)
  92. end;
  93. symbolic procedure !:rn2rd x;
  94. % Convert rn to rd in dmodes rd and cr if roundall is on.
  95. if !*roundall and !*rounded then !*rn2rd x else x;
  96. symbolic procedure !:times(u,v);
  97. % We assume neither u nor v can be 0.
  98. if null u or null v then nil
  99. else if atom u and atom v then u*v
  100. else dcombine(u,v,'times);
  101. symbolic procedure !:zerop u;
  102. if null u or u=0 then t
  103. else if atom u then nil
  104. else apply1(get(car u,'zerop),u);
  105. symbolic procedure fieldp u;
  106. % U is a domain element. Value is T if U is invertable, NIL
  107. % otherwise.
  108. not atom u and flagp(car u,'field);
  109. symbolic procedure gettransferfn(u,v);
  110. % This may be unnecessary. If dmodechk has been called, then all
  111. % transfer functions should be defined.
  112. (if x then x else dmoderr(u,v)) where x=get(u,v);
  113. symbolic procedure dcombine(u,v,fn);
  114. % U and V are domain elements, but not both atoms (integers).
  115. % FN is a binary function on domain elements;
  116. % Value is the domain element representing FN(U,V)
  117. % or pair of domain elements representing divide(u,v).
  118. <<u := if atom u
  119. then apply2(get(car v,fn),apply1(get(car v,'i2d),u),v)
  120. else if atom v
  121. then apply2(get(car u,fn),u,apply1(get(car u,'i2d),v))
  122. else if car u eq car v then apply2(get(car u,fn),u,v) else
  123. % convert anything to :ps: but not the reverse;
  124. % convert real to complex, never the reverse;
  125. % also convert rn or crn to rd or cr but not the reverse:
  126. % hence crn or gi plus rd requires that *both* convert to cr.
  127. (<<if (not(x and atom x)
  128. or (get(du,'cmpxfn) and not get(dv,'cmpxfn)
  129. or du memq dl and not(dv memq dl)) and dv neq '!:ps!:)
  130. % extra test added above by Alan Barnes to ensure
  131. % result is :ps: if either operand is a :ps:
  132. and not flagp(dv,'noconvert) then
  133. % convert v -> u but may first have to convert u.
  134. <<if du memq dml and dv eq '!:rd!:
  135. or du eq '!:rd!: and dv memq dml then
  136. <<u := apply1(get(du,'!:cr!:),u); du := '!:cr!:>>
  137. else if du eq '!:rn!: and dv eq '!:gi!:
  138. or du eq '!:gi!: and dv eq '!:rn!: then
  139. <<u := apply1(get(du,'!:crn!:),u); du := '!:crn!:>>;
  140. v := apply1(get(dv,du),v); x := get(du,fn)>>
  141. else <<u := apply1(x,u); x := get(dv,fn)>>;
  142. apply2(x,u,v)>>
  143. where x=get(du,dv),dml='(!:crn!: !:gi!:),dl='(!:rd!: !:cr!:))
  144. where du=car u,dv=car v;
  145. if !*rounded and !*roundall and not atom u then
  146. % atom test added by Alan Barnes in case a power series
  147. % operation has already produced an integer.
  148. int!-equiv!-chk
  149. if (v := car u) eq '!:rn!: and cddr u neq 1 then !*rn2rd u
  150. else if v eq '!:crn!: and (cdadr u neq 1 or cdddr u neq 1)
  151. then !*crn2cr u
  152. else u
  153. else if fn eq 'divide then % Modified by Francis Wright.
  154. int!-equiv!-chk car u . int!-equiv!-chk cdr u
  155. else int!-equiv!-chk u>>;
  156. symbolic procedure int!-equiv!-chk u;
  157. % U is a domain element. If U can be converted to 0, result is NIL,
  158. % if U can be converted to 1, result is 1,
  159. % if U is a rational or a complex rational and can be converted to
  160. % an integer, result is that integer,
  161. % if *convert is on and U can be converted to an integer, result
  162. % is that integer. Otherwise, U is returned.
  163. % In most cases, U will be structured.
  164. if !*noequiv then u
  165. else begin scalar x;
  166. if atom u then return if u=0 then nil else u
  167. else if apply1(get(car u,'zerop),u) then return nil
  168. else if apply1(get(car u,'onep),u) then return 1
  169. % else if null !*convert then return u
  170. else if (x := get(car u,'intequivfn)) and (x := apply1(x,u))
  171. then return if x=0 then nil else x
  172. else return u
  173. end;
  174. % symbolic procedure minuschk u;
  175. % if eqcar(u,'minus)
  176. % and (numberp cadr u
  177. % or not atom cadr u and idp caadr u and get(caadr u,'dname))
  178. % then !:minus cadr u
  179. % else u;
  180. endmodule;
  181. end;