math.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
  32. begin
  33. result:=Get8087CW;
  34. end;
  35. procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
  36. begin
  37. Set8087CW(cw);
  38. end;
  39. procedure Handle_I8086_Error(InterruptNumber : dword); public name 'FPC_HANDLE_I8086_ERROR';
  40. var
  41. FpuStatus : word;
  42. OutError : byte;
  43. begin
  44. OutError:=InterruptNumber;
  45. case byte(InterruptNumber) of
  46. 0 : OutError:=200; {'Division by Zero'}
  47. 5 : OutError:=201; {'Bounds Check', not caught yet }
  48. 12 : OutError:=202; {'Stack Fault', not caught yet }
  49. 7, {'Coprocessor not available', not caught yet }
  50. 9, {'Coprocessor overrun', not caught yet }
  51. 16,$75 :
  52. begin
  53. { This needs special handling }
  54. { to discriminate between 205,206 and 207 }
  55. asm
  56. fnstsw fpustatus { This for is available for 8086 already }
  57. fnclex
  58. end;
  59. if (FpuStatus and FPU_Invalid)<>0 then
  60. OutError:=216
  61. else if (FpuStatus and FPU_Denormal)<>0 then
  62. OutError:=216
  63. else if (FpuStatus and FPU_DivisionByZero)<>0 then
  64. OutError:=208
  65. else if (FpuStatus and FPU_Overflow)<>0 then
  66. OutError:=205
  67. else if (FpuStatus and FPU_Underflow)<>0 then
  68. OutError:=206
  69. else
  70. OutError:=207; {'Coprocessor Error'}
  71. { if exceptions then Reset FPU and reload control word }
  72. if (FPUStatus and FPU_ExceptionMask)<>0 then
  73. SysResetFPU;
  74. end;
  75. end;
  76. HandleError(OutError);
  77. end;
  78. {****************************************************************************
  79. EXTENDED data type routines
  80. ****************************************************************************}
  81. {$define FPC_SYSTEM_HAS_ABS}
  82. function fpc_abs_real(d : ValReal) : ValReal;compilerproc;
  83. begin
  84. { Function is handled internal in the compiler }
  85. runerror(207);
  86. result:=0;
  87. end;
  88. {$define FPC_SYSTEM_HAS_SQR}
  89. function fpc_sqr_real(d : ValReal) : ValReal;compilerproc;
  90. begin
  91. { Function is handled internal in the compiler }
  92. runerror(207);
  93. result:=0;
  94. end;
  95. {$define FPC_SYSTEM_HAS_SQRT}
  96. function fpc_sqrt_real(d : ValReal) : ValReal;compilerproc;
  97. begin
  98. { Function is handled internal in the compiler }
  99. runerror(207);
  100. result:=0;
  101. end;
  102. {$define FPC_SYSTEM_HAS_LN}
  103. function fpc_ln_real(d : ValReal) : ValReal;compilerproc;
  104. begin
  105. { Function is handled internal in the compiler }
  106. runerror(207);
  107. result:=0;
  108. end;
  109. const
  110. { the exact binary representation of pi (as generated by the fldpi instruction),
  111. and then divided by 2 and 4. I've tested the following FPUs and they produce
  112. the exact same values:
  113. i8087
  114. Pentium III (Coppermine)
  115. Athlon 64 (K8)
  116. }
  117. Extended_PIO2: array [0..4] of word=($C235,$2168,$DAA2,$C90F,$3FFF); { pi/2 }
  118. Extended_PIO4: array [0..4] of word=($C235,$2168,$DAA2,$C90F,$3FFE); { pi/4 }
  119. {$define FPC_SYSTEM_HAS_ARCTAN}
  120. function fpc_arctan_real(d : ValReal) : ValReal;assembler;compilerproc;
  121. var
  122. sw: word;
  123. asm
  124. { the fpatan instruction on the 8087 and 80287 has the following restrictions:
  125. 0 <= ST(1) < ST(0) < +inf
  126. which makes it useful only for calculating arctan in the range:
  127. 0 <= d < 1
  128. so in order to cover the full range, we use the following properties of arctan:
  129. arctan(1) = pi/4
  130. arctan(-d) = -arctan(d)
  131. arctan(d) = pi/2 - arctan(1/d), if d>0
  132. }
  133. fld tbyte [d]
  134. ftst
  135. fstsw sw
  136. mov ah, byte [sw + 1]
  137. sahf
  138. jb @@negative
  139. { d >= 0 }
  140. fld1 // 1 d
  141. fcom
  142. fstsw sw
  143. mov ah, byte [sw + 1]
  144. sahf
  145. jb @@greater_than_one
  146. jz @@equal_to_one
  147. { 0 <= d < 1 }
  148. fpatan
  149. jmp @@done
  150. @@greater_than_one:
  151. { d > 1 }
  152. fxch st(1) // d 1
  153. fpatan // arctan(1/d)
  154. fld tbyte [Extended_PIO2] // pi/2 arctan(1/d)
  155. fsubrp st(1), st // pi/2-arctan(1/d)
  156. jmp @@done
  157. @@equal_to_one:
  158. { d = 1, return pi/4 }
  159. fstp st
  160. fstp st
  161. fld tbyte [Extended_PIO4]
  162. jmp @@done
  163. @@negative:
  164. { d < 0; -d > 0 }
  165. fchs // -d
  166. fld1 // 1 -d
  167. fcom
  168. fstsw sw
  169. mov ah, byte [sw + 1]
  170. sahf
  171. jb @@less_than_minus_one
  172. jz @@equal_to_minus_one
  173. { -1 < d < 0; 0 < -d < 1 }
  174. fpatan // arctan(-d)
  175. fchs // -arctan(-d)
  176. jmp @@done
  177. @@equal_to_minus_one:
  178. { d = -1, return -pi/4 }
  179. fstp st
  180. fstp st
  181. fld tbyte [Extended_PIO4]
  182. fchs
  183. jmp @@done
  184. @@less_than_minus_one:
  185. { d < -1; -d > 1 }
  186. fxch st(1) // -d 1
  187. fpatan // arctan(-1/d)
  188. fld tbyte [Extended_PIO2] // pi/2 arctan(-1/d)
  189. fsubp st(1), st // arctan(-1/d)-pi/2
  190. @@done:
  191. end;
  192. {$define FPC_SYSTEM_HAS_EXP}
  193. function fpc_exp_real(d : ValReal) : ValReal;assembler;compilerproc;
  194. var
  195. sw1: word;
  196. asm
  197. // comes from DJ GPP
  198. { fixed for 8087 and 80287 by nickysn
  199. notable differences between 8087/80287 and 80387:
  200. f2xm1 on 8087/80287 requires that 0<=st(0)<=0.5
  201. f2xm1 on 80387+ requires that -1<=st(0)<=1
  202. fscale on 8087/80287 requires that -2**15<=st(1)<=0 or 1<=st(1)<2**15
  203. fscale on 80387+ has no restrictions
  204. }
  205. fld tbyte[d] // d
  206. fldl2e // l2e d
  207. fmulp st(1), st // l2e*d
  208. fld st(0) // l2e*d l2e*d
  209. frndint // round(l2e*d) l2e*d
  210. fxch st(1) // l2e*d round(l2e*d)
  211. fsub st, st(1) // l2e*d-round(l2e*d) round(l2e*d)
  212. ftst // l2e*d-round(l2e*d)<0?
  213. fstsw sw1
  214. mov ah, byte [sw1 + 1]
  215. sahf
  216. jb @@negative
  217. f2xm1 // 2**(l2e*d-round(l2e*d))-1 round(l2e*d)
  218. fld1 // 1 2**(l2e*d-round(l2e*d))-1 round(l2e*d)
  219. faddp st(1), st // 2**(l2e*d-round(l2e*d)) round(l2e*d)
  220. jmp @@common
  221. @@negative:
  222. fchs // -l2e*d+round(l2e*d) round(l2e*d)
  223. f2xm1 // 2**(-l2e*d+round(l2e*d))-1 round(l2e*d)
  224. fld1 // 1 2**(-l2e*d+round(l2e*d))-1 round(l2e*d)
  225. fadd st(1), st // 1 2**(-l2e*d+round(l2e*d)) round(l2e*d)
  226. fdivrp st(1), st // 2**(l2e*d-round(l2e*d)) round(l2e*d)
  227. @@common:
  228. fscale // (2**(l2e*d-round(l2e*d)))*(2**round(l2e*d)) round(l2e*d)
  229. fstp st(1) // (2**(l2e*d-round(l2e*d)))*(2**round(l2e*d))
  230. end;
  231. {$define FPC_SYSTEM_HAS_FRAC}
  232. function fpc_frac_real(d : ValReal) : ValReal;assembler;compilerproc;
  233. asm
  234. sub sp, 2
  235. mov bx, sp
  236. fnstcw ss:[bx]
  237. fwait
  238. mov cl, ss:[bx+1]
  239. or byte ss:[bx+1], $0f
  240. fldcw ss:[bx]
  241. fld tbyte [d]
  242. frndint
  243. fld tbyte [d]
  244. fsub st, st(1)
  245. fstp st(1)
  246. mov ss:[bx+1], cl
  247. fldcw ss:[bx]
  248. add sp, 2
  249. end;
  250. {$define FPC_SYSTEM_HAS_INT}
  251. function fpc_int_real(d : ValReal) : ValReal;assembler;compilerproc;
  252. asm
  253. sub sp, 2
  254. mov bx, sp
  255. fnstcw ss:[bx]
  256. fwait
  257. mov cl, byte ss:[bx+1]
  258. or byte ss:[bx+1], $0f
  259. fldcw ss:[bx]
  260. fwait
  261. fld tbyte [d]
  262. frndint
  263. fwait
  264. mov byte ss:[bx+1], cl
  265. fldcw ss:[bx]
  266. add sp, 2
  267. end;
  268. {$define FPC_SYSTEM_HAS_TRUNC}
  269. function fpc_trunc_real(d : ValReal) : int64;assembler;compilerproc;
  270. asm
  271. sub sp, 10
  272. mov bx, sp
  273. fld tbyte [d]
  274. fnstcw ss:[bx]
  275. mov cl, ss:[bx+1]
  276. or byte ss:[bx+1], $0f
  277. fldcw ss:[bx]
  278. mov ss:[bx+1], cl
  279. fistp qword ss:[bx+2]
  280. fldcw ss:[bx]
  281. fwait
  282. mov dx, ss:[bx+2]
  283. mov cx, ss:[bx+4]
  284. mov ax, ss:[bx+8]
  285. { store bx as last }
  286. mov bx, ss:[bx+6]
  287. add sp, 10
  288. end;
  289. {$define FPC_SYSTEM_HAS_ROUND}
  290. function fpc_round_real(d : ValReal) : int64;assembler;compilerproc;
  291. var
  292. tmp: int64;
  293. asm
  294. fld tbyte [d]
  295. fistp qword [tmp]
  296. fwait
  297. mov dx, [tmp]
  298. mov cx, [tmp+2]
  299. mov bx, [tmp+4]
  300. mov ax, [tmp+6]
  301. end;