math.inc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2003 by the Free Pascal development team.
  4. Implementation of mathematical Routines (for extended type)
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************
  12. FPU Control word
  13. ****************************************************************************}
  14. procedure Set8087CW(cw:word);
  15. begin
  16. { pic-safe ; cw will not be a regvar because it's accessed from }
  17. { assembler }
  18. default8087cw:=cw;
  19. asm
  20. fnclex
  21. fldcw cw
  22. end;
  23. end;
  24. function Get8087CW:word;assembler;
  25. asm
  26. push ax
  27. mov bx, sp
  28. fnstcw word ptr ss:[bx]
  29. pop ax
  30. end;
  31. {****************************************************************************
  32. EXTENDED data type routines
  33. ****************************************************************************}
  34. {$define FPC_SYSTEM_HAS_PI}
  35. function fpc_pi_real : ValReal;compilerproc;
  36. begin
  37. { Function is handled internal in the compiler }
  38. runerror(207);
  39. result:=0;
  40. end;
  41. {$define FPC_SYSTEM_HAS_ABS}
  42. function fpc_abs_real(d : ValReal) : ValReal;compilerproc;
  43. begin
  44. { Function is handled internal in the compiler }
  45. runerror(207);
  46. result:=0;
  47. end;
  48. {$define FPC_SYSTEM_HAS_SQR}
  49. function fpc_sqr_real(d : ValReal) : ValReal;compilerproc;
  50. begin
  51. { Function is handled internal in the compiler }
  52. runerror(207);
  53. result:=0;
  54. end;
  55. {$define FPC_SYSTEM_HAS_SQRT}
  56. function fpc_sqrt_real(d : ValReal) : ValReal;compilerproc;
  57. begin
  58. { Function is handled internal in the compiler }
  59. runerror(207);
  60. result:=0;
  61. end;
  62. {$define FPC_SYSTEM_HAS_LN}
  63. function fpc_ln_real(d : ValReal) : ValReal;compilerproc;
  64. begin
  65. { Function is handled internal in the compiler }
  66. runerror(207);
  67. result:=0;
  68. end;
  69. const
  70. { the exact binary representation of pi (as generated by the fldpi instruction),
  71. and then divided by 2 and 4. I've tested the following FPUs and they produce
  72. the exact same values:
  73. i8087
  74. Pentium III (Coppermine)
  75. Athlon 64 (K8)
  76. }
  77. Extended_PIO2: array [0..4] of word=($C235,$2168,$DAA2,$C90F,$3FFF); { pi/2 }
  78. Extended_PIO4: array [0..4] of word=($C235,$2168,$DAA2,$C90F,$3FFE); { pi/4 }
  79. {$define FPC_SYSTEM_HAS_ARCTAN}
  80. function fpc_arctan_real(d : ValReal) : ValReal;assembler;compilerproc;
  81. var
  82. sw: word;
  83. asm
  84. { the fpatan instruction on the 8087 and 80287 has the following restrictions:
  85. 0 <= ST(1) < ST(0) < +inf
  86. which makes it useful only for calculating arctan in the range:
  87. 0 <= d < 1
  88. so in order to cover the full range, we use the following properties of arctan:
  89. arctan(1) = pi/4
  90. arctan(-d) = -arctan(d)
  91. arctan(d) = pi/2 - arctan(1/d), if d>0
  92. }
  93. fld tbyte [d]
  94. ftst
  95. fstsw sw
  96. mov ah, [sw + 1]
  97. sahf
  98. jb @@negative
  99. { d >= 0 }
  100. fld1 // 1 d
  101. fcom
  102. fstsw sw
  103. mov ah, [sw + 1]
  104. sahf
  105. jb @@greater_than_one
  106. jz @@equal_to_one
  107. { 0 <= d < 1 }
  108. fpatan
  109. jmp @@done
  110. @@greater_than_one:
  111. { d > 1 }
  112. fxch st(1) // d 1
  113. fpatan // arctan(1/d)
  114. fld tbyte [Extended_PIO2] // pi/2 arctan(1/d)
  115. fsubrp st(1), st // pi/2-arctan(1/d)
  116. jmp @@done
  117. @@equal_to_one:
  118. { d = 1, return pi/4 }
  119. fstp st
  120. fstp st
  121. fld tbyte [Extended_PIO4]
  122. jmp @@done
  123. @@negative:
  124. { d < 0; -d > 0 }
  125. fchs // -d
  126. fld1 // 1 -d
  127. fcom
  128. fstsw sw
  129. mov ah, [sw + 1]
  130. sahf
  131. jb @@less_than_minus_one
  132. jz @@equal_to_minus_one
  133. { -1 < d < 0; 0 < -d < 1 }
  134. fpatan // arctan(-d)
  135. fchs // -arctan(-d)
  136. jmp @@done
  137. @@equal_to_minus_one:
  138. { d = -1, return -pi/4 }
  139. fstp st
  140. fstp st
  141. fld tbyte [Extended_PIO4]
  142. fchs
  143. jmp @@done
  144. @@less_than_minus_one:
  145. { d < -1; -d > 1 }
  146. fxch st(1) // -d 1
  147. fpatan // arctan(-1/d)
  148. fld tbyte [Extended_PIO2] // pi/2 arctan(-1/d)
  149. fsubp st(1), st // arctan(-1/d)-pi/2
  150. @@done:
  151. end;
  152. {$define FPC_SYSTEM_HAS_EXP}
  153. function fpc_exp_real(d : ValReal) : ValReal;assembler;compilerproc;
  154. var
  155. sw1: word;
  156. asm
  157. // comes from DJ GPP
  158. { fixed for 8087 and 80287 by nickysn
  159. notable differences between 8087/80287 and 80387:
  160. f2xm1 on 8087/80287 requires that 0<=st(0)<=0.5
  161. f2xm1 on 80387+ requires that -1<=st(0)<=1
  162. fscale on 8087/80287 requires that -2**15<=st(1)<=0 or 1<=st(1)<2**15
  163. fscale on 80387+ has no restrictions
  164. }
  165. fld tbyte[d] // d
  166. fldl2e // l2e d
  167. fmulp st(1), st // l2e*d
  168. fld st(0) // l2e*d l2e*d
  169. frndint // round(l2e*d) l2e*d
  170. fxch st(1) // l2e*d round(l2e*d)
  171. fsub st, st(1) // l2e*d-round(l2e*d) round(l2e*d)
  172. ftst // l2e*d-round(l2e*d)<0?
  173. fstsw sw1
  174. mov ah, [sw1 + 1]
  175. sahf
  176. jb @@negative
  177. f2xm1 // 2**(l2e*d-round(l2e*d))-1 round(l2e*d)
  178. fld1 // 1 2**(l2e*d-round(l2e*d))-1 round(l2e*d)
  179. faddp st(1), st // 2**(l2e*d-round(l2e*d)) round(l2e*d)
  180. jmp @@common
  181. @@negative:
  182. fchs // -l2e*d+round(l2e*d) round(l2e*d)
  183. f2xm1 // 2**(-l2e*d+round(l2e*d))-1 round(l2e*d)
  184. fld1 // 1 2**(-l2e*d+round(l2e*d))-1 round(l2e*d)
  185. fadd st(1), st // 1 2**(-l2e*d+round(l2e*d)) round(l2e*d)
  186. fdivrp st(1), st // 2**(l2e*d-round(l2e*d)) round(l2e*d)
  187. @@common:
  188. fscale // (2**(l2e*d-round(l2e*d)))*(2**round(l2e*d)) round(l2e*d)
  189. fstp st(1) // (2**(l2e*d-round(l2e*d)))*(2**round(l2e*d))
  190. end;
  191. {$define FPC_SYSTEM_HAS_FRAC}
  192. function fpc_frac_real(d : ValReal) : ValReal;assembler;compilerproc;
  193. asm
  194. sub sp, 2
  195. fnstcw [bp-2]
  196. fwait
  197. mov cl, [bp-1]
  198. or byte [bp-1], $0f
  199. fldcw [bp-2]
  200. fld tbyte [d]
  201. frndint
  202. fld tbyte [d]
  203. fsub st, st(1)
  204. fstp st(1)
  205. mov [bp-1], cl
  206. fldcw [bp-2]
  207. end;
  208. {$define FPC_SYSTEM_HAS_INT}
  209. function fpc_int_real(d : ValReal) : ValReal;assembler;compilerproc;
  210. asm
  211. sub sp, 2
  212. fnstcw [bp-2]
  213. fwait
  214. mov cl, byte [bp-1]
  215. or byte [bp-1], $0f
  216. fldcw [bp-2]
  217. fwait
  218. fld tbyte [d]
  219. frndint
  220. fwait
  221. mov byte [bp-1], cl
  222. fldcw [bp-2]
  223. end;
  224. {$define FPC_SYSTEM_HAS_TRUNC}
  225. function fpc_trunc_real(d : ValReal) : int64;assembler;compilerproc;
  226. asm
  227. sub sp, 10
  228. fld tbyte [d]
  229. fnstcw [bp-10]
  230. mov cl, [bp-9]
  231. or byte [bp-9], $0f
  232. fldcw [bp-10]
  233. mov [bp-9], cl
  234. fistp qword [bp-8]
  235. fldcw [bp-10]
  236. fwait
  237. mov dx, [bp-8]
  238. mov cx, [bp-6]
  239. mov bx, [bp-4]
  240. mov ax, [bp-2]
  241. end;
  242. {$define FPC_SYSTEM_HAS_ROUND}
  243. function fpc_round_real(d : ValReal) : int64;assembler;compilerproc;
  244. var
  245. tmp: int64;
  246. asm
  247. fld tbyte [d]
  248. fistp qword [tmp]
  249. fwait
  250. mov dx, [tmp]
  251. mov cx, [tmp+2]
  252. mov bx, [tmp+4]
  253. mov ax, [tmp+6]
  254. end;