math.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2000 by Jonas Maebe and other members of the
  5. Free Pascal development team
  6. Implementation of mathamatical Routines (only for real)
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. const
  14. longint_to_real_helper: int64 = $4330000080000000;
  15. cardinal_to_real_helper: int64 = $430000000000000;
  16. int_to_real_factor: double = double(high(cardinal))+1.0;
  17. {****************************************************************************
  18. EXTENDED data type routines
  19. ****************************************************************************}
  20. {$define FPC_SYSTEM_HAS_PI}
  21. function pi : double;[internproc:in_pi];
  22. {$define FPC_SYSTEM_HAS_ABS}
  23. function abs(d : extended) : extended;[internproc:in_abs_extended];
  24. {$define FPC_SYSTEM_HAS_SQR}
  25. function sqr(d : extended) : extended;[internproc:in_sqr_extended];
  26. {$define FPC_SYSTEM_HAS_SQRT}
  27. function sqrt(d : extended) : extended;[internproc:in_sqrt_extended];
  28. {
  29. function arctan(d : extended) : extended;[internconst:in_arctan_extended];
  30. begin
  31. runerror(207);
  32. end;
  33. function ln(d : extended) : extended;[internconst:in_ln_extended];
  34. begin
  35. runerror(207);
  36. end;
  37. function sin(d : extended) : extended;[internconst: in_sin_extended];
  38. begin
  39. runerror(207);
  40. end;
  41. function cos(d : extended) : extended;[internconst:in_cos_extended];
  42. begin
  43. runerror(207);
  44. end;
  45. function exp(d : extended) : extended;[internconst:in_const_exp];
  46. begin
  47. runerror(207);
  48. end;
  49. }
  50. const
  51. factor: double = double(int64(1) shl 32);
  52. factor2: double = double(int64(1) shl 31);
  53. {$define FPC_SYSTEM_HAS_TRUNC}
  54. function trunc(d : extended) : int64;assembler;[internconst:in_const_trunc];
  55. { input: d in fr1 }
  56. { output: result in r3 }
  57. assembler;
  58. var
  59. temp: packed record
  60. case byte of
  61. 0: (l1,l2: longint);
  62. 1: (d: double);
  63. end;
  64. asm
  65. // store d in temp
  66. stfd f1, temp
  67. // extract sign bit (record in cr0)
  68. lwz r3,temp
  69. rlwinm. r3,r3,1,31,31
  70. // make d positive
  71. fabs f1,f1
  72. // load 2^32 in f2
  73. {$ifndef macos}
  74. lis r3,factor@ha
  75. lfd f2,factor@l(r3)
  76. {$else}
  77. lwz r3,factor[TC](r2)
  78. lfd f2,0(r3)
  79. {$endif}
  80. // check if value is < 0
  81. // f3 := d / 2^32;
  82. fdiv f3,f1,f2
  83. // round
  84. fctiwz f4,f3
  85. // store
  86. stfd f4,temp
  87. // and load into r4
  88. lwz r4,4+temp
  89. // convert back to float
  90. lis r0,0x4330
  91. stw r0,temp
  92. xoris r0,r4,0x8000
  93. stw r0,4+temp
  94. {$ifndef macos}
  95. lis r3,longint_to_real_helper@ha
  96. lfd f0,longint_to_real_helper@l(r3)
  97. {$else}
  98. lwz r3,longint_to_real_helper[TC](r2)
  99. lfd f0,0(r3)
  100. {$endif}
  101. lfd f3,temp
  102. fsub f3,f3,f0
  103. // f4 := d "mod" 2^32 ( = d - ((d / 2^32) * 2^32))
  104. fnmsub f4,f3,f2,f1
  105. // now, convert to unsigned 32 bit
  106. // load 2^31 in f2
  107. {$ifndef macos}
  108. lis r3,factor2@ha
  109. lfd f2,factor2@l(r3)
  110. {$else}
  111. lwz r3,factor2[TC](r2)
  112. lfd f2,0(r3)
  113. {$endif}
  114. // subtract 2^31
  115. fsub f3,f4,f2
  116. // was the value > 2^31?
  117. fcmpu cr1,f4,f2
  118. // use diff if >= 2^31
  119. fsel f4,f3,f3,f4
  120. // next part same as conversion to signed integer word
  121. fctiwz f4,f4
  122. stfd f4,temp
  123. lwz r3,4+temp
  124. // add 2^31 if value was >=2^31
  125. blt cr1, LTruncNoAdd
  126. xoris r3,r3,0x8000
  127. LTruncNoAdd:
  128. // negate value if it was negative to start with
  129. beq cr0,LTruncPositive
  130. subfic r3,r3,0
  131. subfze r4,r4
  132. LTruncPositive:
  133. end ['R3','R4','F1','F2','F3','F4'];
  134. {$define FPC_SYSTEM_HAS_ROUND}
  135. {$ifdef hascompilerproc}
  136. function round(d : extended) : int64;[internconst:in_const_round, external name 'FPC_ROUND'];
  137. function fpc_round(d : extended) : int64;assembler;[public, alias:'FPC_ROUND'];{$ifdef hascompilerproc}compilerproc;{$endif hascompilerproc}
  138. {$else}
  139. function round(d : extended) : int64;assembler;[internconst:in_const_round];
  140. {$endif hascompilerproc}
  141. { input: d in fr1 }
  142. { output: result in r3 }
  143. assembler;
  144. var
  145. temp : packed record
  146. case byte of
  147. 0: (l1,l2: longint);
  148. 1: (d: double);
  149. end;
  150. asm
  151. fctiw f1,f1
  152. stfd f1,temp
  153. lwz r3,temp
  154. lwz r4,4+temp
  155. end ['R3','F1'];
  156. {$define FPC_SYSTEM_HAS_POWER}
  157. function power(bas,expo : extended) : extended;
  158. begin
  159. if bas=0 then
  160. begin
  161. if expo<>0 then
  162. power:=0.0
  163. else
  164. HandleError(207);
  165. end
  166. else if expo=0 then
  167. power:=1
  168. else
  169. { bas < 0 is not allowed }
  170. if bas<0 then
  171. handleerror(207)
  172. else
  173. power:=exp(ln(bas)*expo);
  174. end;
  175. {****************************************************************************
  176. Longint data type routines
  177. ****************************************************************************}
  178. {$define FPC_SYSTEM_HAS_POWER_INT64}
  179. function power(bas,expo : int64) : int64;
  180. begin
  181. if bas=0 then
  182. begin
  183. if expo<>0 then
  184. power:=0
  185. else
  186. HandleError(207);
  187. end
  188. else if expo=0 then
  189. power:=1
  190. else
  191. begin
  192. if bas<0 then
  193. begin
  194. if odd(expo) then
  195. power:=-round(exp(ln(-bas)*expo))
  196. else
  197. power:=round(exp(ln(-bas)*expo));
  198. end
  199. else
  200. power:=round(exp(ln(bas)*expo));
  201. end;
  202. end;
  203. {****************************************************************************
  204. Helper routines to support old TP styled reals
  205. ****************************************************************************}
  206. { warning: the following converts a little-endian TP-style real }
  207. { to a big-endian double. So don't byte-swap the TP real! }
  208. {$define FPC_SYSTEM_HAS_REAL2DOUBLE}
  209. function real2double(r : real48) : double;
  210. var
  211. res : array[0..7] of byte;
  212. exponent : word;
  213. begin
  214. { copy mantissa }
  215. res[6]:=0;
  216. res[5]:=r[1] shl 5;
  217. res[4]:=(r[1] shr 3) or (r[2] shl 5);
  218. res[3]:=(r[2] shr 3) or (r[3] shl 5);
  219. res[2]:=(r[3] shr 3) or (r[4] shl 5);
  220. res[1]:=(r[4] shr 3) or (r[5] and $7f) shl 5;
  221. res[0]:=(r[5] and $7f) shr 3;
  222. { copy exponent }
  223. { correct exponent: }
  224. exponent:=(word(r[0])+(1023-129));
  225. res[1]:=res[1] or ((exponent and $f) shl 4);
  226. res[0]:=exponent shr 4;
  227. { set sign }
  228. res[0]:=res[0] or (r[5] and $80);
  229. real2double:=double(res);
  230. end;
  231. {****************************************************************************
  232. Int to real helpers
  233. ****************************************************************************}
  234. function fpc_int64_to_double(i: int64): double; compilerproc;
  235. assembler;
  236. { input: high(i) in r3, low(i) in r4 }
  237. { output: double(i) in f0 }
  238. var
  239. temp: packed record
  240. case byte of
  241. 0: (l1,l2: cardinal);
  242. 1: (d: double);
  243. end;
  244. asm
  245. lis r0,0x4330
  246. stw r0,temp
  247. xoris r3,r3,0x8000
  248. stw r3,4+temp
  249. {$ifndef macos}
  250. lis r3,longint_to_real_helper@ha
  251. lfd f1,longint_to_real_helper@l(r3)
  252. {$else}
  253. lwz r3,longint_to_real_helper[TC](r2)
  254. lfd f1,0(r3)
  255. {$endif}
  256. lfd f0,temp
  257. stw r4,4+temp
  258. fsub f0,f0,f1
  259. {$ifndef macos}
  260. lis r4,cardinal_to_real_helper@ha
  261. lfd f1,cardinal_to_real_helper@l(r4)
  262. lis r3,int_to_real_factor@ha
  263. lfd f3,temp
  264. lfd f2,int_to_real_factor@l(r3)
  265. {$else}
  266. lwz r4,cardinal_to_real_helper[TC](r2)
  267. lwz r3,int_to_real_factor[TC](r2)
  268. lfd f3,temp
  269. lfd f1,0(r4)
  270. lfd f2,0(r3)
  271. {$endif}
  272. fsub f3,f3,f1
  273. fmadd f1,f0,f2,f3
  274. end ['R0','R3','R4','F0','F1','F2','F3'];
  275. function fpc_qword_to_double(q: qword): double; compilerproc;
  276. assembler;
  277. { input: high(q) in r3, low(q) in r4 }
  278. { output: double(q) in f0 }
  279. var
  280. temp: packed record
  281. case byte of
  282. 0: (l1,l2: cardinal);
  283. 1: (d: double);
  284. end;
  285. asm
  286. lis r0,0x4330
  287. stw r0,temp
  288. stw r3,4+temp
  289. lfd f0,temp
  290. {$ifndef macos}
  291. lis r3,cardinal_to_real_helper@ha
  292. lfd f1,cardinal_to_real_helper@l(r3)
  293. {$else}
  294. lwz r3,longint_to_real_helper[TC](r2)
  295. lfd f1,0(r3)
  296. {$endif}
  297. stw r4,4+temp
  298. fsub f0,f0,f1
  299. lfd f3,temp
  300. {$ifndef macos}
  301. lis r3,int_to_real_factor@ha
  302. lfd f2,int_to_real_factor@l(r3)
  303. {$else}
  304. lwz r3,int_to_real_factor[TC](r2)
  305. lfd f2,0(r3)
  306. {$endif}
  307. fsub f3,f3,f1
  308. fmadd f1,f0,f2,f3
  309. end ['R0','R3','F0','F1','F2','F3'];
  310. {
  311. $Log$
  312. Revision 1.20 2003-05-02 15:12:19 jonas
  313. - removed empty ppc-specific frac()
  314. + added correct generic frac() implementation for doubles (translated
  315. from glibc code)
  316. Revision 1.19 2003/04/26 20:36:24 jonas
  317. * trunc now also supports int64 (no NaN's etc though)
  318. Revision 1.18 2003/04/26 17:20:16 florian
  319. * fixed trunc, now it's working at least for longint range
  320. Revision 1.17 2003/04/23 21:28:21 peter
  321. * fpc_round added, needed for int64 currency
  322. Revision 1.16 2003/01/16 11:29:11 olle
  323. * changed access of globals to be indirect via TOC
  324. Revision 1.15 2003/01/15 01:09:04 florian
  325. * changed power(...) prototype to int64
  326. Revision 1.14 2002/11/28 11:04:16 olle
  327. * macos: refs to globals in asm adapted to macos
  328. Revision 1.13 2002/10/21 18:08:28 jonas
  329. * round has int64 instead of longint result
  330. Revision 1.12 2002/09/08 13:00:21 jonas
  331. * made pi an internproc instead of internconst
  332. Revision 1.11 2002/09/07 16:01:26 peter
  333. * old logs removed and tabs fixed
  334. Revision 1.10 2002/08/18 22:11:10 florian
  335. * fixed remaining assembler errors
  336. Revision 1.9 2002/08/18 21:37:48 florian
  337. * several errors in inline assembler fixed
  338. Revision 1.8 2002/08/10 17:14:36 jonas
  339. * various fixes, mostly changing the names of the modifies registers to
  340. upper case since that seems to be required by the compiler
  341. Revision 1.7 2002/07/31 16:58:12 jonas
  342. * fixed conversion from int64/qword to double errors
  343. Revision 1.6 2002/07/29 21:28:17 florian
  344. * several fixes to get further with linux/ppc system unit compilation
  345. Revision 1.5 2002/07/28 21:39:29 florian
  346. * made abs a compiler proc if it is generic
  347. Revision 1.4 2002/07/28 20:43:49 florian
  348. * several fixes for linux/powerpc
  349. * several fixes to MT
  350. }