math.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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 = $4330000000000000;
  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. { exactly the same as trunc, except that one fctiwz has become fctiw }
  142. { input: d in fr1 }
  143. { output: result in r3 }
  144. assembler;
  145. var
  146. temp: packed record
  147. case byte of
  148. 0: (l1,l2: longint);
  149. 1: (d: double);
  150. end;
  151. asm
  152. // store d in temp
  153. stfd f1, temp
  154. // extract sign bit (record in cr0)
  155. lwz r3,temp
  156. rlwinm. r3,r3,1,31,31
  157. // make d positive
  158. fabs f1,f1
  159. // load 2^32 in f2
  160. {$ifndef macos}
  161. lis r3,factor@ha
  162. lfd f2,factor@l(r3)
  163. {$else}
  164. lwz r3,factor[TC](r2)
  165. lfd f2,0(r3)
  166. {$endif}
  167. // check if value is < 0
  168. // f3 := d / 2^32;
  169. fdiv f3,f1,f2
  170. // round
  171. fctiwz f4,f3
  172. // store
  173. stfd f4,temp
  174. // and load into r4
  175. lwz r4,4+temp
  176. // convert back to float
  177. lis r0,0x4330
  178. stw r0,temp
  179. xoris r0,r4,0x8000
  180. stw r0,4+temp
  181. {$ifndef macos}
  182. lis r3,longint_to_real_helper@ha
  183. lfd f0,longint_to_real_helper@l(r3)
  184. {$else}
  185. lwz r3,longint_to_real_helper[TC](r2)
  186. lfd f0,0(r3)
  187. {$endif}
  188. lfd f3,temp
  189. fsub f3,f3,f0
  190. // f4 := d "mod" 2^32 ( = d - ((d / 2^32) * 2^32))
  191. fnmsub f4,f3,f2,f1
  192. // now, convert to unsigned 32 bit
  193. // load 2^31 in f2
  194. {$ifndef macos}
  195. lis r3,factor2@ha
  196. lfd f2,factor2@l(r3)
  197. {$else}
  198. lwz r3,factor2[TC](r2)
  199. lfd f2,0(r3)
  200. {$endif}
  201. // subtract 2^31
  202. fsub f3,f4,f2
  203. // was the value > 2^31?
  204. fcmpu cr1,f4,f2
  205. // use diff if >= 2^31
  206. fsel f4,f3,f3,f4
  207. // next part same as conversion to signed integer word
  208. fctiw f4,f4
  209. stfd f4,temp
  210. lwz r3,4+temp
  211. // add 2^31 if value was >=2^31
  212. blt cr1, LRoundNoAdd
  213. xoris r3,r3,0x8000
  214. LRoundNoAdd:
  215. // negate value if it was negative to start with
  216. beq cr0,LRoundPositive
  217. subfic r3,r3,0
  218. subfze r4,r4
  219. LRoundPositive:
  220. end ['R3','R4','F1','F2','F3','F4'];
  221. {$define FPC_SYSTEM_HAS_POWER}
  222. function power(bas,expo : extended) : extended;
  223. begin
  224. if bas=0 then
  225. begin
  226. if expo<>0 then
  227. power:=0.0
  228. else
  229. HandleError(207);
  230. end
  231. else if expo=0 then
  232. power:=1
  233. else
  234. { bas < 0 is not allowed }
  235. if bas<0 then
  236. handleerror(207)
  237. else
  238. power:=exp(ln(bas)*expo);
  239. end;
  240. {****************************************************************************
  241. Longint data type routines
  242. ****************************************************************************}
  243. {$define FPC_SYSTEM_HAS_POWER_INT64}
  244. function power(bas,expo : int64) : int64;
  245. begin
  246. if bas=0 then
  247. begin
  248. if expo<>0 then
  249. power:=0
  250. else
  251. HandleError(207);
  252. end
  253. else if expo=0 then
  254. power:=1
  255. else
  256. begin
  257. if bas<0 then
  258. begin
  259. if odd(expo) then
  260. power:=-round(exp(ln(-bas)*expo))
  261. else
  262. power:=round(exp(ln(-bas)*expo));
  263. end
  264. else
  265. power:=round(exp(ln(bas)*expo));
  266. end;
  267. end;
  268. {****************************************************************************
  269. Helper routines to support old TP styled reals
  270. ****************************************************************************}
  271. { warning: the following converts a little-endian TP-style real }
  272. { to a big-endian double. So don't byte-swap the TP real! }
  273. {$define FPC_SYSTEM_HAS_REAL2DOUBLE}
  274. function real2double(r : real48) : double;
  275. var
  276. res : array[0..7] of byte;
  277. exponent : word;
  278. begin
  279. { copy mantissa }
  280. res[6]:=0;
  281. res[5]:=r[1] shl 5;
  282. res[4]:=(r[1] shr 3) or (r[2] shl 5);
  283. res[3]:=(r[2] shr 3) or (r[3] shl 5);
  284. res[2]:=(r[3] shr 3) or (r[4] shl 5);
  285. res[1]:=(r[4] shr 3) or (r[5] and $7f) shl 5;
  286. res[0]:=(r[5] and $7f) shr 3;
  287. { copy exponent }
  288. { correct exponent: }
  289. exponent:=(word(r[0])+(1023-129));
  290. res[1]:=res[1] or ((exponent and $f) shl 4);
  291. res[0]:=exponent shr 4;
  292. { set sign }
  293. res[0]:=res[0] or (r[5] and $80);
  294. real2double:=double(res);
  295. end;
  296. {****************************************************************************
  297. Int to real helpers
  298. ****************************************************************************}
  299. function fpc_int64_to_double(i: int64): double; compilerproc;
  300. assembler;
  301. { input: high(i) in r4, low(i) in r3 }
  302. { output: double(i) in f0 }
  303. var
  304. temp: packed record
  305. case byte of
  306. 0: (l1,l2: cardinal);
  307. 1: (d: double);
  308. end;
  309. asm
  310. lis r0,0x4330
  311. stw r0,temp
  312. xoris r4,r4,0x8000
  313. stw r4,4+temp
  314. {$ifndef macos}
  315. lis r4,longint_to_real_helper@ha
  316. lfd f1,longint_to_real_helper@l(r4)
  317. {$else}
  318. lwz r4,longint_to_real_helper[TC](r2)
  319. lfd f1,0(r4)
  320. {$endif}
  321. lfd f0,temp
  322. stw r3,4+temp
  323. fsub f0,f0,f1
  324. {$ifndef macos}
  325. lis r3,cardinal_to_real_helper@ha
  326. lfd f1,cardinal_to_real_helper@l(r3)
  327. lis r3,int_to_real_factor@ha
  328. lfd f3,temp
  329. lfd f2,int_to_real_factor@l(r3)
  330. {$else}
  331. lwz r3,cardinal_to_real_helper[TC](r2)
  332. lwz r4,int_to_real_factor[TC](r2)
  333. lfd f3,temp
  334. lfd f1,0(r3)
  335. lfd f2,0(r4)
  336. {$endif}
  337. fsub f3,f3,f1
  338. fmadd f1,f0,f2,f3
  339. end ['R0','R3','R4','F0','F1','F2','F3'];
  340. function fpc_qword_to_double(q: qword): double; compilerproc;
  341. assembler;
  342. { input: high(q) in r4, low(q) in r3 }
  343. { output: double(q) in f0 }
  344. var
  345. temp: packed record
  346. case byte of
  347. 0: (l1,l2: cardinal);
  348. 1: (d: double);
  349. end;
  350. asm
  351. lis r0,0x4330
  352. stw r0,temp
  353. stw r4,4+temp
  354. lfd f0,temp
  355. {$ifndef macos}
  356. lis r4,cardinal_to_real_helper@ha
  357. lfd f1,cardinal_to_real_helper@l(r4)
  358. {$else}
  359. lwz r4,longint_to_real_helper[TC](r2)
  360. lfd f1,0(r4)
  361. {$endif}
  362. stw r3,4+temp
  363. fsub f0,f0,f1
  364. lfd f3,temp
  365. {$ifndef macos}
  366. lis r3,int_to_real_factor@ha
  367. lfd f2,int_to_real_factor@l(r3)
  368. {$else}
  369. lwz r3,int_to_real_factor[TC](r2)
  370. lfd f2,0(r3)
  371. {$endif}
  372. fsub f3,f3,f1
  373. fmadd f1,f0,f2,f3
  374. end ['R0','R3','F0','F1','F2','F3'];
  375. {
  376. $Log$
  377. Revision 1.22 2003-05-16 16:04:33 jonas
  378. * fixed round() (almost the same as trunc)
  379. Revision 1.21 2003/05/11 18:09:45 jonas
  380. * fixed qword and int64 to double conversion
  381. Revision 1.20 2003/05/02 15:12:19 jonas
  382. - removed empty ppc-specific frac()
  383. + added correct generic frac() implementation for doubles (translated
  384. from glibc code)
  385. Revision 1.19 2003/04/26 20:36:24 jonas
  386. * trunc now also supports int64 (no NaN's etc though)
  387. Revision 1.18 2003/04/26 17:20:16 florian
  388. * fixed trunc, now it's working at least for longint range
  389. Revision 1.17 2003/04/23 21:28:21 peter
  390. * fpc_round added, needed for int64 currency
  391. Revision 1.16 2003/01/16 11:29:11 olle
  392. * changed access of globals to be indirect via TOC
  393. Revision 1.15 2003/01/15 01:09:04 florian
  394. * changed power(...) prototype to int64
  395. Revision 1.14 2002/11/28 11:04:16 olle
  396. * macos: refs to globals in asm adapted to macos
  397. Revision 1.13 2002/10/21 18:08:28 jonas
  398. * round has int64 instead of longint result
  399. Revision 1.12 2002/09/08 13:00:21 jonas
  400. * made pi an internproc instead of internconst
  401. Revision 1.11 2002/09/07 16:01:26 peter
  402. * old logs removed and tabs fixed
  403. Revision 1.10 2002/08/18 22:11:10 florian
  404. * fixed remaining assembler errors
  405. Revision 1.9 2002/08/18 21:37:48 florian
  406. * several errors in inline assembler fixed
  407. Revision 1.8 2002/08/10 17:14:36 jonas
  408. * various fixes, mostly changing the names of the modifies registers to
  409. upper case since that seems to be required by the compiler
  410. Revision 1.7 2002/07/31 16:58:12 jonas
  411. * fixed conversion from int64/qword to double errors
  412. Revision 1.6 2002/07/29 21:28:17 florian
  413. * several fixes to get further with linux/ppc system unit compilation
  414. Revision 1.5 2002/07/28 21:39:29 florian
  415. * made abs a compiler proc if it is generic
  416. Revision 1.4 2002/07/28 20:43:49 florian
  417. * several fixes for linux/powerpc
  418. * several fixes to MT
  419. }