math.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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 mathematical 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;
  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 r4,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;
  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. {$define FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  298. function fpc_int64_to_double(i: int64): double; compilerproc;
  299. assembler;
  300. { input: high(i) in r4, low(i) in r3 }
  301. { output: double(i) in f0 }
  302. var
  303. temp: packed record
  304. case byte of
  305. 0: (l1,l2: cardinal);
  306. 1: (d: double);
  307. end;
  308. asm
  309. lis r0,0x4330
  310. stw r0,temp
  311. xoris r3,r3,0x8000
  312. stw r3,4+temp
  313. {$ifndef macos}
  314. lis r3,longint_to_real_helper@ha
  315. lfd f1,longint_to_real_helper@l(r3)
  316. {$else}
  317. lwz r3,longint_to_real_helper[TC](r2)
  318. lfd f1,0(r3)
  319. {$endif}
  320. lfd f0,temp
  321. stw r4,4+temp
  322. fsub f0,f0,f1
  323. {$ifndef macos}
  324. lis r4,cardinal_to_real_helper@ha
  325. lfd f1,cardinal_to_real_helper@l(r4)
  326. lis r4,int_to_real_factor@ha
  327. lfd f3,temp
  328. lfd f2,int_to_real_factor@l(r4)
  329. {$else}
  330. lwz r4,cardinal_to_real_helper[TC](r2)
  331. lwz r3,int_to_real_factor[TC](r2)
  332. lfd f3,temp
  333. lfd f1,0(r4)
  334. lfd f2,0(r3)
  335. {$endif}
  336. fsub f3,f3,f1
  337. fmadd f1,f0,f2,f3
  338. end;
  339. {$define FPC_SYSTEM_HAS_QWORD_TO_DOUBLE}
  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 r3,4+temp
  354. lfd f0,temp
  355. {$ifndef macos}
  356. lis r3,cardinal_to_real_helper@ha
  357. lfd f1,cardinal_to_real_helper@l(r3)
  358. {$else}
  359. lwz r3,longint_to_real_helper[TC](r2)
  360. lfd f1,0(r3)
  361. {$endif}
  362. stw r4,4+temp
  363. fsub f0,f0,f1
  364. lfd f3,temp
  365. {$ifndef macos}
  366. lis r4,int_to_real_factor@ha
  367. lfd f2,int_to_real_factor@l(r4)
  368. {$else}
  369. lwz r4,int_to_real_factor[TC](r2)
  370. lfd f2,0(r4)
  371. {$endif}
  372. fsub f3,f3,f1
  373. fmadd f1,f0,f2,f3
  374. end;
  375. {
  376. $Log$
  377. Revision 1.29 2003-09-04 16:07:31 florian
  378. * fixed qword_to_double conversion on powerpc
  379. Revision 1.28 2003/09/03 14:09:37 florian
  380. * arm fixes to the common rtl code
  381. * some generic math code fixed
  382. * ...
  383. Revision 1.27 2003/08/08 22:02:05 olle
  384. * small bugfix macos
  385. Revision 1.26 2003/06/14 12:41:08 jonas
  386. * fixed compilation problems (removed unnecessary modified registers
  387. lists from procedures)
  388. Revision 1.25 2003/05/31 20:22:06 jonas
  389. * fixed 64 bit results of trunc and round
  390. Revision 1.24 2003/05/30 23:56:41 florian
  391. * fixed parameter passing for int64
  392. Revision 1.23 2003/05/24 13:39:32 jonas
  393. * fsqrt is an optional instruction in the ppc architecture and isn't
  394. implemented by any current ppc afaik, so use the generic sqrt routine
  395. instead (adapted so it works with compilerproc)
  396. Revision 1.22 2003/05/16 16:04:33 jonas
  397. * fixed round() (almost the same as trunc)
  398. Revision 1.21 2003/05/11 18:09:45 jonas
  399. * fixed qword and int64 to double conversion
  400. Revision 1.20 2003/05/02 15:12:19 jonas
  401. - removed empty ppc-specific frac()
  402. + added correct generic frac() implementation for doubles (translated
  403. from glibc code)
  404. Revision 1.19 2003/04/26 20:36:24 jonas
  405. * trunc now also supports int64 (no NaN's etc though)
  406. Revision 1.18 2003/04/26 17:20:16 florian
  407. * fixed trunc, now it's working at least for longint range
  408. Revision 1.17 2003/04/23 21:28:21 peter
  409. * fpc_round added, needed for int64 currency
  410. Revision 1.16 2003/01/16 11:29:11 olle
  411. * changed access of globals to be indirect via TOC
  412. Revision 1.15 2003/01/15 01:09:04 florian
  413. * changed power(...) prototype to int64
  414. Revision 1.14 2002/11/28 11:04:16 olle
  415. * macos: refs to globals in asm adapted to macos
  416. Revision 1.13 2002/10/21 18:08:28 jonas
  417. * round has int64 instead of longint result
  418. Revision 1.12 2002/09/08 13:00:21 jonas
  419. * made pi an internproc instead of internconst
  420. Revision 1.11 2002/09/07 16:01:26 peter
  421. * old logs removed and tabs fixed
  422. Revision 1.10 2002/08/18 22:11:10 florian
  423. * fixed remaining assembler errors
  424. Revision 1.9 2002/08/18 21:37:48 florian
  425. * several errors in inline assembler fixed
  426. Revision 1.8 2002/08/10 17:14:36 jonas
  427. * various fixes, mostly changing the names of the modifies registers to
  428. upper case since that seems to be required by the compiler
  429. Revision 1.7 2002/07/31 16:58:12 jonas
  430. * fixed conversion from int64/qword to double errors
  431. Revision 1.6 2002/07/29 21:28:17 florian
  432. * several fixes to get further with linux/ppc system unit compilation
  433. Revision 1.5 2002/07/28 21:39:29 florian
  434. * made abs a compiler proc if it is generic
  435. Revision 1.4 2002/07/28 20:43:49 florian
  436. * several fixes for linux/powerpc
  437. * several fixes to MT
  438. }