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_ABS}
  35. function fpc_abs_real(d : ValReal) : 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_SQR}
  42. function fpc_sqr_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_SQRT}
  49. function fpc_sqrt_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_LN}
  56. function fpc_ln_real(d : ValReal) : ValReal;compilerproc;
  57. begin
  58. { Function is handled internal in the compiler }
  59. runerror(207);
  60. result:=0;
  61. end;
  62. const
  63. { the exact binary representation of pi (as generated by the fldpi instruction),
  64. and then divided by 2 and 4. I've tested the following FPUs and they produce
  65. the exact same values:
  66. i8087
  67. Pentium III (Coppermine)
  68. Athlon 64 (K8)
  69. }
  70. Extended_PIO2: array [0..4] of word=($C235,$2168,$DAA2,$C90F,$3FFF); { pi/2 }
  71. Extended_PIO4: array [0..4] of word=($C235,$2168,$DAA2,$C90F,$3FFE); { pi/4 }
  72. {$define FPC_SYSTEM_HAS_ARCTAN}
  73. function fpc_arctan_real(d : ValReal) : ValReal;assembler;compilerproc;
  74. var
  75. sw: word;
  76. asm
  77. { the fpatan instruction on the 8087 and 80287 has the following restrictions:
  78. 0 <= ST(1) < ST(0) < +inf
  79. which makes it useful only for calculating arctan in the range:
  80. 0 <= d < 1
  81. so in order to cover the full range, we use the following properties of arctan:
  82. arctan(1) = pi/4
  83. arctan(-d) = -arctan(d)
  84. arctan(d) = pi/2 - arctan(1/d), if d>0
  85. }
  86. fld tbyte [d]
  87. ftst
  88. fstsw sw
  89. mov ah, [sw + 1]
  90. sahf
  91. jb @@negative
  92. { d >= 0 }
  93. fld1 // 1 d
  94. fcom
  95. fstsw sw
  96. mov ah, [sw + 1]
  97. sahf
  98. jb @@greater_than_one
  99. jz @@equal_to_one
  100. { 0 <= d < 1 }
  101. fpatan
  102. jmp @@done
  103. @@greater_than_one:
  104. { d > 1 }
  105. fxch st(1) // d 1
  106. fpatan // arctan(1/d)
  107. fld tbyte [Extended_PIO2] // pi/2 arctan(1/d)
  108. fsubrp st(1), st // pi/2-arctan(1/d)
  109. jmp @@done
  110. @@equal_to_one:
  111. { d = 1, return pi/4 }
  112. fstp st
  113. fstp st
  114. fld tbyte [Extended_PIO4]
  115. jmp @@done
  116. @@negative:
  117. { d < 0; -d > 0 }
  118. fchs // -d
  119. fld1 // 1 -d
  120. fcom
  121. fstsw sw
  122. mov ah, [sw + 1]
  123. sahf
  124. jb @@less_than_minus_one
  125. jz @@equal_to_minus_one
  126. { -1 < d < 0; 0 < -d < 1 }
  127. fpatan // arctan(-d)
  128. fchs // -arctan(-d)
  129. jmp @@done
  130. @@equal_to_minus_one:
  131. { d = -1, return -pi/4 }
  132. fstp st
  133. fstp st
  134. fld tbyte [Extended_PIO4]
  135. fchs
  136. jmp @@done
  137. @@less_than_minus_one:
  138. { d < -1; -d > 1 }
  139. fxch st(1) // -d 1
  140. fpatan // arctan(-1/d)
  141. fld tbyte [Extended_PIO2] // pi/2 arctan(-1/d)
  142. fsubp st(1), st // arctan(-1/d)-pi/2
  143. @@done:
  144. end;
  145. {$define FPC_SYSTEM_HAS_EXP}
  146. function fpc_exp_real(d : ValReal) : ValReal;assembler;compilerproc;
  147. var
  148. sw1: word;
  149. asm
  150. // comes from DJ GPP
  151. { fixed for 8087 and 80287 by nickysn
  152. notable differences between 8087/80287 and 80387:
  153. f2xm1 on 8087/80287 requires that 0<=st(0)<=0.5
  154. f2xm1 on 80387+ requires that -1<=st(0)<=1
  155. fscale on 8087/80287 requires that -2**15<=st(1)<=0 or 1<=st(1)<2**15
  156. fscale on 80387+ has no restrictions
  157. }
  158. fld tbyte[d] // d
  159. fldl2e // l2e d
  160. fmulp st(1), st // l2e*d
  161. fld st(0) // l2e*d l2e*d
  162. frndint // round(l2e*d) l2e*d
  163. fxch st(1) // l2e*d round(l2e*d)
  164. fsub st, st(1) // l2e*d-round(l2e*d) round(l2e*d)
  165. ftst // l2e*d-round(l2e*d)<0?
  166. fstsw sw1
  167. mov ah, [sw1 + 1]
  168. sahf
  169. jb @@negative
  170. f2xm1 // 2**(l2e*d-round(l2e*d))-1 round(l2e*d)
  171. fld1 // 1 2**(l2e*d-round(l2e*d))-1 round(l2e*d)
  172. faddp st(1), st // 2**(l2e*d-round(l2e*d)) round(l2e*d)
  173. jmp @@common
  174. @@negative:
  175. fchs // -l2e*d+round(l2e*d) round(l2e*d)
  176. f2xm1 // 2**(-l2e*d+round(l2e*d))-1 round(l2e*d)
  177. fld1 // 1 2**(-l2e*d+round(l2e*d))-1 round(l2e*d)
  178. fadd st(1), st // 1 2**(-l2e*d+round(l2e*d)) round(l2e*d)
  179. fdivrp st(1), st // 2**(l2e*d-round(l2e*d)) round(l2e*d)
  180. @@common:
  181. fscale // (2**(l2e*d-round(l2e*d)))*(2**round(l2e*d)) round(l2e*d)
  182. fstp st(1) // (2**(l2e*d-round(l2e*d)))*(2**round(l2e*d))
  183. end;
  184. {$define FPC_SYSTEM_HAS_FRAC}
  185. function fpc_frac_real(d : ValReal) : ValReal;assembler;compilerproc;
  186. asm
  187. sub sp, 2
  188. mov bx, sp
  189. fnstcw ss:[bx]
  190. fwait
  191. mov cl, ss:[bx+1]
  192. or byte ss:[bx+1], $0f
  193. fldcw ss:[bx]
  194. fld tbyte [d]
  195. frndint
  196. fld tbyte [d]
  197. fsub st, st(1)
  198. fstp st(1)
  199. mov ss:[bx+1], cl
  200. fldcw ss:[bx]
  201. add sp, 2
  202. end;
  203. {$define FPC_SYSTEM_HAS_INT}
  204. function fpc_int_real(d : ValReal) : ValReal;assembler;compilerproc;
  205. asm
  206. sub sp, 2
  207. mov bx, sp
  208. fnstcw ss:[bx]
  209. fwait
  210. mov cl, byte ss:[bx+1]
  211. or byte ss:[bx+1], $0f
  212. fldcw ss:[bx]
  213. fwait
  214. fld tbyte [d]
  215. frndint
  216. fwait
  217. mov byte ss:[bx+1], cl
  218. fldcw ss:[bx]
  219. add sp, 2
  220. end;
  221. {$define FPC_SYSTEM_HAS_TRUNC}
  222. function fpc_trunc_real(d : ValReal) : int64;assembler;compilerproc;
  223. asm
  224. sub sp, 10
  225. mov bx, sp
  226. fld tbyte [d]
  227. fnstcw ss:[bx]
  228. mov cl, ss:[bx+1]
  229. or byte ss:[bx+1], $0f
  230. fldcw ss:[bx]
  231. mov ss:[bx+1], cl
  232. fistp qword ss:[bx+2]
  233. fldcw ss:[bx]
  234. fwait
  235. mov dx, ss:[bx+2]
  236. mov cx, ss:[bx+4]
  237. mov ax, ss:[bx+8]
  238. { store bx as last }
  239. mov bx, ss:[bx+6]
  240. add sp, 10
  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;