math.inc 14 KB

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