genmath.inc 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2001 by Several contributors
  4. Generic mathemtical routines (on type real)
  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. { Credits }
  13. {*************************************************************************}
  14. { Copyright Abandoned, 1987, Fred Fish }
  15. { }
  16. { This previously copyrighted work has been placed into the }
  17. { public domain by the author (Fred Fish) and may be freely used }
  18. { for any purpose, private or commercial. I would appreciate }
  19. { it, as a courtesy, if this notice is left in all copies and }
  20. { derivative works. Thank you, and enjoy... }
  21. { }
  22. { The author makes no warranty of any kind with respect to this }
  23. { product and explicitly disclaims any implied warranties of }
  24. { merchantability or fitness for any particular purpose. }
  25. {-------------------------------------------------------------------------}
  26. { Copyright (c) 1992 Odent Jean Philippe }
  27. { }
  28. { The source can be modified as long as my name appears and some }
  29. { notes explaining the modifications done are included in the file. }
  30. {-------------------------------------------------------------------------}
  31. { Copyright (c) 1997 Carl Eric Codere }
  32. {-------------------------------------------------------------------------}
  33. {$goto on}
  34. type
  35. TabCoef = array[0..6] of Real;
  36. const
  37. PIO2 = 1.57079632679489661923; { pi/2 }
  38. PIO4 = 7.85398163397448309616E-1; { pi/4 }
  39. SQRT2 = 1.41421356237309504880; { sqrt(2) }
  40. SQRTH = 7.07106781186547524401E-1; { sqrt(2)/2 }
  41. LOG2E = 1.4426950408889634073599; { 1/log(2) }
  42. SQ2OPI = 7.9788456080286535587989E-1; { sqrt( 2/pi )}
  43. LOGE2 = 6.93147180559945309417E-1; { log(2) }
  44. LOGSQ2 = 3.46573590279972654709E-1; { log(2)/2 }
  45. THPIO4 = 2.35619449019234492885; { 3*pi/4 }
  46. TWOOPI = 6.36619772367581343075535E-1; { 2/pi }
  47. lossth = 1.073741824e9;
  48. MAXLOG = 8.8029691931113054295988E1; { log(2**127) }
  49. MINLOG = -8.872283911167299960540E1; { log(2**-128) }
  50. DP1 = 7.85398125648498535156E-1;
  51. DP2 = 3.77489470793079817668E-8;
  52. DP3 = 2.69515142907905952645E-15;
  53. const sincof : TabCoef = (
  54. 1.58962301576546568060E-10,
  55. -2.50507477628578072866E-8,
  56. 2.75573136213857245213E-6,
  57. -1.98412698295895385996E-4,
  58. 8.33333333332211858878E-3,
  59. -1.66666666666666307295E-1, 0);
  60. coscof : TabCoef = (
  61. -1.13585365213876817300E-11,
  62. 2.08757008419747316778E-9,
  63. -2.75573141792967388112E-7,
  64. 2.48015872888517045348E-5,
  65. -1.38888888888730564116E-3,
  66. 4.16666666666665929218E-2, 0);
  67. { also necessary for Int() on systems with 64bit floats (JM) }
  68. type
  69. {$ifdef ENDIAN_LITTLE}
  70. float64 = packed record
  71. low: longint;
  72. high: longint;
  73. end;
  74. {$else}
  75. float64 = packed record
  76. high: longint;
  77. low: longint;
  78. end;
  79. {$endif}
  80. {$ifndef FPC_SYSTEM_HAS_TRUNC}
  81. type
  82. float32 = longint;
  83. flag = byte;
  84. Function extractFloat64Frac0(const a: float64): longint;
  85. Begin
  86. extractFloat64Frac0 := a.high and $000FFFFF;
  87. End;
  88. Function extractFloat64Frac1(const a: float64): longint;
  89. Begin
  90. extractFloat64Frac1 := a.low;
  91. End;
  92. Function extractFloat64Exp(const a: float64): smallint;
  93. Begin
  94. extractFloat64Exp:= ( a.high shr 20 ) AND $7FF;
  95. End;
  96. Function extractFloat64Frac(const a: float64): int64;
  97. Begin
  98. extractFloat64Frac:=int64(a) and $000FFFFFFFFFFFFF;
  99. End;
  100. Function extractFloat64Sign(const a: float64) : flag;
  101. Begin
  102. extractFloat64Sign := a.high shr 31;
  103. End;
  104. Procedure shortShift64Left(a0:longint; a1:longint; count:smallint; VAR z0Ptr:longint; VAR z1Ptr:longint );
  105. Begin
  106. z1Ptr := a1 shl count;
  107. if count = 0 then
  108. z0Ptr := a0
  109. else
  110. z0Ptr := ( a0 shl count ) OR ( a1 shr ( ( - count ) AND 31 ) );
  111. End;
  112. function float64_to_int32_round_to_zero(a: float64 ): longint;
  113. Var
  114. aSign: flag;
  115. aExp, shiftCount: smallint;
  116. aSig0, aSig1, absZ, aSigExtra: longint;
  117. z: longint;
  118. Begin
  119. aSig1 := extractFloat64Frac1( a );
  120. aSig0 := extractFloat64Frac0( a );
  121. aExp := extractFloat64Exp( a );
  122. aSign := extractFloat64Sign( a );
  123. shiftCount := aExp - $413;
  124. if 0<=shiftCount then
  125. Begin
  126. if (aExp=$7FF) and ((aSig0 or aSig1)<>0) then
  127. HandleError(207);
  128. shortShift64Left(aSig0 OR $00100000, aSig1, shiftCount, absZ, aSigExtra );
  129. End
  130. else
  131. Begin
  132. if aExp<$3FF then
  133. begin
  134. float64_to_int32_round_to_zero := 0;
  135. exit;
  136. end;
  137. aSig0 := aSig0 or $00100000;
  138. aSigExtra := ( aSig0 shl ( shiftCount and 31 ) ) OR aSig1;
  139. absZ := aSig0 shr ( - shiftCount );
  140. End;
  141. if aSign<>0 then
  142. z:=-absZ
  143. else
  144. z:=absZ;
  145. if ((aSign<>0) xor (z<0)) AND (z<>0) then
  146. HandleError(207);
  147. float64_to_int32_round_to_zero := z;
  148. End;
  149. function float64_to_int64_round_to_zero(a : float64) : int64;
  150. var
  151. aSign : flag;
  152. aExp, shiftCount : smallint;
  153. aSig : int64;
  154. z : int64;
  155. begin
  156. aSig:=extractFloat64Frac(a);
  157. aExp:=extractFloat64Exp(a);
  158. aSign:=extractFloat64Sign(a);
  159. if aExp<>0 then
  160. aSig:=aSig or $0010000000000000;
  161. shiftCount:= aExp-$433;
  162. if 0<=shiftCount then
  163. begin
  164. if aExp>=$43e then
  165. begin
  166. if int64(a)<>$C3E0000000000000 then
  167. HandleError(207);
  168. { pascal doesn't know Inf for int64 }
  169. HandleError(207);
  170. end;
  171. z:=aSig shl shiftCount;
  172. end
  173. else
  174. begin
  175. if aExp<$3fe then
  176. begin
  177. result:=0;
  178. exit;
  179. end;
  180. z:=aSig shr -shiftCount;
  181. {
  182. if (aSig shl (shiftCount and 63))<>0 then
  183. float_exception_flags |= float_flag_inexact;
  184. }
  185. end;
  186. if aSign<>0 then
  187. z:=-z;
  188. result:=z;
  189. end;
  190. Function ExtractFloat32Frac(a : Float32) : longint;
  191. Begin
  192. ExtractFloat32Frac := A AND $007FFFFF;
  193. End;
  194. Function extractFloat32Exp( a: float32 ): smallint;
  195. Begin
  196. extractFloat32Exp := (a shr 23) AND $FF;
  197. End;
  198. Function extractFloat32Sign( a: float32 ): Flag;
  199. Begin
  200. extractFloat32Sign := a shr 31;
  201. End;
  202. Function float32_to_int32_round_to_zero( a: Float32 ): longint;
  203. Var
  204. aSign : flag;
  205. aExp, shiftCount : smallint;
  206. aSig : longint;
  207. z : longint;
  208. Begin
  209. aSig := extractFloat32Frac( a );
  210. aExp := extractFloat32Exp( a );
  211. aSign := extractFloat32Sign( a );
  212. shiftCount := aExp - $9E;
  213. if ( 0 <= shiftCount ) then
  214. Begin
  215. if ( a <> Float32($CF000000) ) then
  216. Begin
  217. if ( (aSign=0) or ( ( aExp = $FF ) and (aSig<>0) ) ) then
  218. Begin
  219. HandleError(207);
  220. exit;
  221. end;
  222. End;
  223. HandleError(207);
  224. exit;
  225. End
  226. else
  227. if ( aExp <= $7E ) then
  228. Begin
  229. float32_to_int32_round_to_zero := 0;
  230. exit;
  231. End;
  232. aSig := ( aSig or $00800000 ) shl 8;
  233. z := aSig shr ( - shiftCount );
  234. if ( aSign<>0 ) then z := - z;
  235. float32_to_int32_round_to_zero := z;
  236. End;
  237. {$ifdef INTERNCONSTINTF}
  238. function fpc_trunc_real(d : real) : int64;compilerproc;
  239. {$else}
  240. function trunc(d : real) : int64;[internconst:fpc_in_const_trunc];
  241. {$endif}
  242. var
  243. {$ifdef cpuarm}
  244. l: longint;
  245. {$endif cpuarm}
  246. f32 : float32;
  247. f64 : float64;
  248. Begin
  249. { in emulation mode the real is equal to a single }
  250. { otherwise in fpu mode, it is equal to a double }
  251. { extended is not supported yet. }
  252. if sizeof(D) > 8 then
  253. HandleError(255);
  254. if sizeof(D)=8 then
  255. begin
  256. move(d,f64,sizeof(f64));
  257. {$ifdef cpuarm}
  258. { the arm fpu has a strange opinion how a double has to be stored }
  259. l:=f64.low;
  260. f64.low:=f64.high;
  261. f64.high:=l;
  262. {$endif cpuarm}
  263. result:=float64_to_int64_round_to_zero(f64);
  264. end
  265. else
  266. begin
  267. move(d,f32,sizeof(f32));
  268. result:=float32_to_int32_round_to_zero(f32);
  269. end;
  270. end;
  271. {$endif}
  272. {$ifndef FPC_SYSTEM_HAS_INT}
  273. {$ifdef SUPPORT_DOUBLE}
  274. { straight Pascal translation of the code for __trunc() in }
  275. { the file sysdeps/libm-ieee754/s_trunc.c of glibc (JM) }
  276. {$ifdef INTERNCONSTINTF}
  277. function fpc_int_real(d: double): double;compilerproc;
  278. {$else}
  279. function int(d: double): double;[internconst:fpc_in_const_int];
  280. {$endif}
  281. var
  282. i0, j0: longint;
  283. i1: cardinal;
  284. sx: longint;
  285. f64 : float64;
  286. begin
  287. f64:=float64(d);
  288. {$ifdef cpuarm}
  289. { the arm fpu has a strange opinion how a double has to be stored }
  290. i0:=f64.low;
  291. f64.low:=f64.high;
  292. f64.high:=i0;
  293. {$endif cpuarm}
  294. i0 := f64.high;
  295. i1 := cardinal(f64.low);
  296. sx := i0 and $80000000;
  297. j0 := ((i0 shr 20) and $7ff) - $3ff;
  298. if (j0 < 20) then
  299. begin
  300. if (j0 < 0) then
  301. begin
  302. { the magnitude of the number is < 1 so the result is +-0. }
  303. f64.high := sx;
  304. f64.low := 0;
  305. end
  306. else
  307. begin
  308. f64.high := sx or (i0 and not($fffff shr j0));
  309. f64.low := 0;
  310. end
  311. end
  312. else if (j0 > 51) then
  313. begin
  314. if (j0 = $400) then
  315. { d is inf or NaN }
  316. exit(d + d); { don't know why they do this (JM) }
  317. end
  318. else
  319. begin
  320. f64.high := i0;
  321. f64.low := longint(i1 and not(cardinal($ffffffff) shr (j0 - 20)));
  322. end;
  323. {$ifdef cpuarm}
  324. { the arm fpu has a strange opinion how a double has to be stored }
  325. i0:=f64.low;
  326. f64.low:=f64.high;
  327. f64.high:=i0;
  328. {$endif cpuarm}
  329. result:=double(f64);
  330. end;
  331. {$else SUPPORT_DOUBLE}
  332. {$ifdef INTERNCONSTINTF}
  333. function fpc_int_real(d : real) : real;compilerproc;
  334. {$else}
  335. function int(d : real) : real;[internconst:fpc_in_const_int];
  336. {$endif}
  337. begin
  338. { this will be correct since real = single in the case of }
  339. { the motorola version of the compiler... }
  340. result:=real(trunc(d));
  341. end;
  342. {$endif SUPPORT_DOUBLE}
  343. {$endif}
  344. {$ifndef FPC_SYSTEM_HAS_ABS}
  345. {$ifdef SUPPORT_DOUBLE}
  346. {$ifdef INTERNCONSTINTF}
  347. function fpc_abs_real(d : Double) : Double;compilerproc;
  348. {$else}
  349. function abs(d : Double) : Double;[public,alias:'FPC_ABS_REAL'];
  350. {$endif}
  351. begin
  352. if (d<0.0) then
  353. result := -d
  354. else
  355. result := d ;
  356. end;
  357. {$else}
  358. {$ifdef INTERNCONSTINTF}
  359. function fpc_abs_real(d : Double) : Double;compilerproc;
  360. {$else}
  361. function abs(d : Real) : Real;[public,alias:'FPC_ABS_REAL'];
  362. {$endif}
  363. begin
  364. if (d<0.0) then
  365. result := -d
  366. else
  367. result := d ;
  368. end;
  369. {$endif}
  370. {$ifndef INTERNCONSTINTF}
  371. {$ifdef hascompilerproc}
  372. function fpc_abs_real(d:Real):Real;compilerproc; external name 'FPC_ABS_REAL';
  373. {$endif hascompilerproc}
  374. {$endif}
  375. {$endif not FPC_SYSTEM_HAS_ABS}
  376. {$ifndef SYSTEM_HAS_FREXP}
  377. function frexp(x:Real; var e:Integer ):Real;
  378. {* frexp() extracts the exponent from x. It returns an integer *}
  379. {* power of two to expnt and the significand between 0.5 and 1 *}
  380. {* to y. Thus x = y * 2**expn. *}
  381. begin
  382. e :=0;
  383. if (abs(x)<0.5) then
  384. While (abs(x)<0.5) do
  385. begin
  386. x := x*2;
  387. Dec(e);
  388. end
  389. else
  390. While (abs(x)>1) do
  391. begin
  392. x := x/2;
  393. Inc(e);
  394. end;
  395. frexp := x;
  396. end;
  397. {$endif not SYSTEM_HAS_FREXP}
  398. {$ifndef SYSTEM_HAS_LDEXP}
  399. function ldexp( x: Real; N: Integer):Real;
  400. {* ldexp() multiplies x by 2**n. *}
  401. var r : Real;
  402. begin
  403. R := 1;
  404. if N>0 then
  405. while N>0 do
  406. begin
  407. R:=R*2;
  408. Dec(N);
  409. end
  410. else
  411. while N<0 do
  412. begin
  413. R:=R/2;
  414. Inc(N);
  415. end;
  416. ldexp := x * R;
  417. end;
  418. {$endif not SYSTEM_HAS_LDEXP}
  419. function polevl(var x:Real; var Coef:TabCoef; N:Integer):Real;
  420. {*****************************************************************}
  421. { Evaluate polynomial }
  422. {*****************************************************************}
  423. { }
  424. { SYNOPSIS: }
  425. { }
  426. { int N; }
  427. { double x, y, coef[N+1], polevl[]; }
  428. { }
  429. { y = polevl( x, coef, N ); }
  430. { }
  431. { DESCRIPTION: }
  432. { }
  433. { Evaluates polynomial of degree N: }
  434. { }
  435. { 2 N }
  436. { y = C + C x + C x +...+ C x }
  437. { 0 1 2 N }
  438. { }
  439. { Coefficients are stored in reverse order: }
  440. { }
  441. { coef[0] = C , ..., coef[N] = C . }
  442. { N 0 }
  443. { }
  444. { The function p1evl() assumes that coef[N] = 1.0 and is }
  445. { omitted from the array. Its calling arguments are }
  446. { otherwise the same as polevl(). }
  447. { }
  448. { SPEED: }
  449. { }
  450. { In the interest of speed, there are no checks for out }
  451. { of bounds arithmetic. This routine is used by most of }
  452. { the functions in the library. Depending on available }
  453. { equipment features, the user may wish to rewrite the }
  454. { program in microcode or assembly language. }
  455. {*****************************************************************}
  456. var ans : Real;
  457. i : Integer;
  458. begin
  459. ans := Coef[0];
  460. for i:=1 to N do
  461. ans := ans * x + Coef[i];
  462. polevl:=ans;
  463. end;
  464. function p1evl(var x:Real; var Coef:TabCoef; N:Integer):Real;
  465. { }
  466. { Evaluate polynomial when coefficient of x is 1.0. }
  467. { Otherwise same as polevl. }
  468. { }
  469. var
  470. ans : Real;
  471. i : Integer;
  472. begin
  473. ans := x + Coef[0];
  474. for i:=1 to N-1 do
  475. ans := ans * x + Coef[i];
  476. p1evl := ans;
  477. end;
  478. {$ifndef FPC_SYSTEM_HAS_SQR}
  479. {$ifdef INTERNCONSTINTF}
  480. function fpc_sqr_real(d : Real) : Real;compilerproc;{$ifdef MATHINLINE}inline;{$endif}
  481. {$else}
  482. function sqr(d : Real) : Real;[internconst:fpc_in_const_sqr];
  483. {$endif}
  484. begin
  485. result := d*d;
  486. end;
  487. {$endif}
  488. {$ifndef FPC_SYSTEM_HAS_PI}
  489. {$ifdef INTERNCONSTINTF}
  490. function fpc_pi_real : Real;compilerproc;{$ifdef MATHINLINE}inline;{$endif}
  491. {$else}
  492. function pi : Real;[internconst:fpc_in_const_pi];
  493. {$endif}
  494. begin
  495. result := 3.1415926535897932385;
  496. end;
  497. {$endif}
  498. {$ifndef FPC_SYSTEM_HAS_SQRT}
  499. {$ifdef INTERNCONSTINTF}
  500. function fpc_sqrt_real(d:Real):Real;compilerproc;
  501. {$else}
  502. {$ifdef hascompilerproc}
  503. function fpc_sqrt_real(d:Real):Real;compilerproc; external name 'FPC_SQRT_REAL';
  504. {$endif hascompilerproc}
  505. function sqrt(d:Real):Real;[internconst:fpc_in_const_sqrt];[public, alias: 'FPC_SQRT_REAL'];
  506. {$endif}
  507. {*****************************************************************}
  508. { Square root }
  509. {*****************************************************************}
  510. { }
  511. { SYNOPSIS: }
  512. { }
  513. { double x, y, sqrt(); }
  514. { }
  515. { y = sqrt( x ); }
  516. { }
  517. { DESCRIPTION: }
  518. { }
  519. { Returns the square root of x. }
  520. { }
  521. { Range reduction involves isolating the power of two of the }
  522. { argument and using a polynomial approximation to obtain }
  523. { a rough value for the square root. Then Heron's iteration }
  524. { is used three times to converge to an accurate value. }
  525. {*****************************************************************}
  526. var e : Integer;
  527. w,z : Real;
  528. begin
  529. if( d <= 0.0 ) then
  530. begin
  531. if( d < 0.0 ) then
  532. HandleError(207);
  533. result := 0.0;
  534. end
  535. else
  536. begin
  537. w := d;
  538. { separate exponent and significand }
  539. z := frexp( d, e );
  540. { approximate square root of number between 0.5 and 1 }
  541. { relative error of approximation = 7.47e-3 }
  542. d := 4.173075996388649989089E-1 + 5.9016206709064458299663E-1 * z;
  543. { adjust for odd powers of 2 }
  544. if odd(e) then
  545. d := d*SQRT2;
  546. { re-insert exponent }
  547. d := ldexp( d, (e div 2) );
  548. { Newton iterations: }
  549. d := 0.5*(d + w/d);
  550. d := 0.5*(d + w/d);
  551. d := 0.5*(d + w/d);
  552. d := 0.5*(d + w/d);
  553. d := 0.5*(d + w/d);
  554. d := 0.5*(d + w/d);
  555. result := d;
  556. end;
  557. end;
  558. {$endif}
  559. {$ifndef FPC_SYSTEM_HAS_EXP}
  560. {$ifdef INTERNCONSTINTF}
  561. function fpc_exp_real(d:Real):Real;compilerproc;
  562. {$else}
  563. function Exp(d:Real):Real;[internconst:fpc_in_const_exp];
  564. {$endif}
  565. {*****************************************************************}
  566. { Exponential Function }
  567. {*****************************************************************}
  568. { }
  569. { SYNOPSIS: }
  570. { }
  571. { double x, y, exp(); }
  572. { }
  573. { y = exp( x ); }
  574. { }
  575. { DESCRIPTION: }
  576. { }
  577. { Returns e (2.71828...) raised to the x power. }
  578. { }
  579. { Range reduction is accomplished by separating the argument }
  580. { into an integer k and fraction f such that }
  581. { }
  582. { x k f }
  583. { e = 2 e. }
  584. { }
  585. { A Pade' form of degree 2/3 is used to approximate exp(f)- 1 }
  586. { in the basic range [-0.5 ln 2, 0.5 ln 2]. }
  587. {*****************************************************************}
  588. const P : TabCoef = (
  589. 1.26183092834458542160E-4,
  590. 3.02996887658430129200E-2,
  591. 1.00000000000000000000E0, 0, 0, 0, 0);
  592. Q : TabCoef = (
  593. 3.00227947279887615146E-6,
  594. 2.52453653553222894311E-3,
  595. 2.27266044198352679519E-1,
  596. 2.00000000000000000005E0, 0 ,0 ,0);
  597. C1 = 6.9335937500000000000E-1;
  598. C2 = 2.1219444005469058277E-4;
  599. var n : Integer;
  600. px, qx, xx : Real;
  601. begin
  602. if( d > MAXLOG) then
  603. HandleError(205)
  604. else
  605. if( d < MINLOG ) then
  606. begin
  607. HandleError(205);
  608. end
  609. else
  610. begin
  611. { Express e**x = e**g 2**n }
  612. { = e**g e**( n loge(2) ) }
  613. { = e**( g + n loge(2) ) }
  614. px := d * LOG2E;
  615. qx := Trunc( px + 0.5 ); { Trunc() truncates toward -infinity. }
  616. n := Trunc(qx);
  617. d := d - qx * C1;
  618. d := d + qx * C2;
  619. { rational approximation for exponential }
  620. { of the fractional part: }
  621. { e**x - 1 = 2x P(x**2)/( Q(x**2) - P(x**2) ) }
  622. xx := d * d;
  623. px := d * polevl( xx, P, 2 );
  624. d := px/( polevl( xx, Q, 3 ) - px );
  625. d := ldexp( d, 1 );
  626. d := d + 1.0;
  627. d := ldexp( d, n );
  628. result := d;
  629. end;
  630. end;
  631. {$endif}
  632. {$ifndef FPC_SYSTEM_HAS_ROUND}
  633. {$ifdef INTERNCONSTINTF}
  634. function fpc_round_real(d : Real) : int64;compilerproc;
  635. {$else}
  636. {$ifdef hascompilerproc}
  637. function round(d : Real) : int64;{$ifndef INTERNCONSTINTF}[internconst:fpc_in_const_round];{$endif} external name 'FPC_ROUND';
  638. function fpc_round(d : Real) : int64;[public, alias:'FPC_ROUND'];{$ifdef hascompilerproc}compilerproc;{$endif hascompilerproc}
  639. {$else}
  640. function round(d : Real) : int64;{$ifndef INTERNCONSTINTF}[internconst:fpc_in_const_round];{$endif}
  641. {$endif hascompilerproc}
  642. {$endif}
  643. var
  644. fr: Real;
  645. tr: Int64;
  646. Begin
  647. fr := abs(Frac(d));
  648. tr := Trunc(d);
  649. if fr > 0.5 then
  650. if d >= 0 then
  651. result:=tr+1
  652. else
  653. result:=tr-1
  654. else
  655. if fr < 0.5 then
  656. result:=tr
  657. else { fr = 0.5 }
  658. { check sign to decide ... }
  659. { as in Turbo Pascal... }
  660. if d >= 0.0 then
  661. result:=tr+1
  662. else
  663. result:=tr;
  664. end;
  665. {$endif}
  666. {$ifdef FPC_CURRENCY_IS_INT64}
  667. function trunc(c : currency) : int64;
  668. type
  669. tmyrec = record
  670. i: int64;
  671. end;
  672. begin
  673. result := int64(tmyrec(c)) div 10000
  674. end;
  675. function trunc(c : comp) : int64;
  676. begin
  677. result := c
  678. end;
  679. function round(c : currency) : int64;
  680. type
  681. tmyrec = record
  682. i: int64;
  683. end;
  684. var
  685. rem, absrem: longint;
  686. begin
  687. { (int64(tmyrec(c))(+/-)5000) div 10000 can overflow }
  688. result := int64(tmyrec(c)) div 10000;
  689. rem := int64(tmyrec(c)) - result * 10000;
  690. absrem := abs(rem);
  691. if (absrem > 5000) or
  692. ((absrem = 5000) and
  693. (rem > 0)) then
  694. if (rem > 0) then
  695. inc(result)
  696. else
  697. dec(result);
  698. end;
  699. function round(c : comp) : int64;
  700. begin
  701. result := c
  702. end;
  703. {$endif FPC_CURRENCY_IS_INT64}
  704. {$ifndef FPC_SYSTEM_HAS_LN}
  705. {$ifdef INTERNCONSTINTF}
  706. function fpc_ln_real(d:Real):Real;compilerproc;
  707. {$else}
  708. function Ln(d:Real):Real;[internconst:fpc_in_const_ln];
  709. {$endif}
  710. {*****************************************************************}
  711. { Natural Logarithm }
  712. {*****************************************************************}
  713. { }
  714. { SYNOPSIS: }
  715. { }
  716. { double x, y, log(); }
  717. { }
  718. { y = ln( x ); }
  719. { }
  720. { DESCRIPTION: }
  721. { }
  722. { Returns the base e (2.718...) logarithm of x. }
  723. { }
  724. { The argument is separated into its exponent and fractional }
  725. { parts. If the exponent is between -1 and +1, the logarithm }
  726. { of the fraction is approximated by }
  727. { }
  728. { log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). }
  729. { }
  730. { Otherwise, setting z = 2(x-1)/x+1), }
  731. { }
  732. { log(x) = z + z**3 P(z)/Q(z). }
  733. { }
  734. {*****************************************************************}
  735. const P : TabCoef = (
  736. { Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
  737. 1/sqrt(2) <= x < sqrt(2) }
  738. 4.58482948458143443514E-5,
  739. 4.98531067254050724270E-1,
  740. 6.56312093769992875930E0,
  741. 2.97877425097986925891E1,
  742. 6.06127134467767258030E1,
  743. 5.67349287391754285487E1,
  744. 1.98892446572874072159E1);
  745. Q : TabCoef = (
  746. 1.50314182634250003249E1,
  747. 8.27410449222435217021E1,
  748. 2.20664384982121929218E2,
  749. 3.07254189979530058263E2,
  750. 2.14955586696422947765E2,
  751. 5.96677339718622216300E1, 0);
  752. { Coefficients for log(x) = z + z**3 P(z)/Q(z),
  753. where z = 2(x-1)/(x+1)
  754. 1/sqrt(2) <= x < sqrt(2) }
  755. R : TabCoef = (
  756. -7.89580278884799154124E-1,
  757. 1.63866645699558079767E1,
  758. -6.41409952958715622951E1, 0, 0, 0, 0);
  759. S : TabCoef = (
  760. -3.56722798256324312549E1,
  761. 3.12093766372244180303E2,
  762. -7.69691943550460008604E2, 0, 0, 0, 0);
  763. var e : Integer;
  764. z, y : Real;
  765. Label Ldone;
  766. begin
  767. if( d <= 0.0 ) then
  768. HandleError(207);
  769. d := frexp( d, e );
  770. { logarithm using log(x) = z + z**3 P(z)/Q(z),
  771. where z = 2(x-1)/x+1) }
  772. if( (e > 2) or (e < -2) ) then
  773. begin
  774. if( d < SQRTH ) then
  775. begin
  776. { 2( 2x-1 )/( 2x+1 ) }
  777. Dec(e, 1);
  778. z := d - 0.5;
  779. y := 0.5 * z + 0.5;
  780. end
  781. else
  782. begin
  783. { 2 (x-1)/(x+1) }
  784. z := d - 0.5;
  785. z := z - 0.5;
  786. y := 0.5 * d + 0.5;
  787. end;
  788. d := z / y;
  789. { /* rational form */ }
  790. z := d*d;
  791. z := d + d * ( z * polevl( z, R, 2 ) / p1evl( z, S, 3 ) );
  792. goto ldone;
  793. end;
  794. { logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) }
  795. if( d < SQRTH ) then
  796. begin
  797. Dec(e, 1);
  798. d := ldexp( d, 1 ) - 1.0; { 2x - 1 }
  799. end
  800. else
  801. d := d - 1.0;
  802. { rational form }
  803. z := d*d;
  804. y := d * ( z * polevl( d, P, 6 ) / p1evl( d, Q, 6 ) );
  805. y := y - ldexp( z, -1 ); { y - 0.5 * z }
  806. z := d + y;
  807. ldone:
  808. { recombine with exponent term }
  809. if( e <> 0 ) then
  810. begin
  811. y := e;
  812. z := z - y * 2.121944400546905827679e-4;
  813. z := z + y * 0.693359375;
  814. end;
  815. result:= z;
  816. end;
  817. {$endif}
  818. {$ifndef FPC_SYSTEM_HAS_SIN}
  819. {$ifdef INTERNCONSTINTF}
  820. function fpc_Sin_real(d:Real):Real;compilerproc;
  821. {$else}
  822. function Sin(d:Real):Real;[internconst:fpc_in_const_sin];
  823. {$endif}
  824. {*****************************************************************}
  825. { Circular Sine }
  826. {*****************************************************************}
  827. { }
  828. { SYNOPSIS: }
  829. { }
  830. { double x, y, sin(); }
  831. { }
  832. { y = sin( x ); }
  833. { }
  834. { DESCRIPTION: }
  835. { }
  836. { Range reduction is into intervals of pi/4. The reduction }
  837. { error is nearly eliminated by contriving an extended }
  838. { precision modular arithmetic. }
  839. { }
  840. { Two polynomial approximating functions are employed. }
  841. { Between 0 and pi/4 the sine is approximated by }
  842. { x + x**3 P(x**2). }
  843. { Between pi/4 and pi/2 the cosine is represented as }
  844. { 1 - x**2 Q(x**2). }
  845. {*****************************************************************}
  846. var y, z, zz : Real;
  847. j, sign : Integer;
  848. begin
  849. { make argument positive but save the sign }
  850. sign := 1;
  851. if( d < 0 ) then
  852. begin
  853. d := -d;
  854. sign := -1;
  855. end;
  856. { above this value, approximate towards 0 }
  857. if( d > lossth ) then
  858. begin
  859. result := 0.0;
  860. exit;
  861. end;
  862. y := Trunc( d/PIO4 ); { integer part of x/PIO4 }
  863. { strip high bits of integer part to prevent integer overflow }
  864. z := ldexp( y, -4 );
  865. z := Trunc(z); { integer part of y/8 }
  866. z := y - ldexp( z, 4 ); { y - 16 * (y/16) }
  867. j := Trunc(z); { convert to integer for tests on the phase angle }
  868. { map zeros to origin }
  869. { typecast is to avoid "can't determine which overloaded function }
  870. { to call" }
  871. if odd( longint(j) ) then
  872. begin
  873. inc(j);
  874. y := y + 1.0;
  875. end;
  876. j := j and 7; { octant modulo 360 degrees }
  877. { reflect in x axis }
  878. if( j > 3) then
  879. begin
  880. sign := -sign;
  881. dec(j, 4);
  882. end;
  883. { Extended precision modular arithmetic }
  884. z := ((d - y * DP1) - y * DP2) - y * DP3;
  885. zz := z * z;
  886. if( (j=1) or (j=2) ) then
  887. y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 )
  888. else
  889. { y = z + z * (zz * polevl( zz, sincof, 5 )); }
  890. y := z + z * z * z * polevl( zz, sincof, 5 );
  891. if(sign < 0) then
  892. y := -y;
  893. result := y;
  894. end;
  895. {$endif}
  896. {$ifndef FPC_SYSTEM_HAS_COS}
  897. {$ifdef INTERNCONSTINTF}
  898. function fpc_Cos_real(d:Real):Real;compilerproc;
  899. {$else}
  900. function Cos(d:Real):Real;[internconst:fpc_in_const_cos];
  901. {$endif}
  902. {*****************************************************************}
  903. { Circular cosine }
  904. {*****************************************************************}
  905. { }
  906. { Circular cosine }
  907. { }
  908. { SYNOPSIS: }
  909. { }
  910. { double x, y, cos(); }
  911. { }
  912. { y = cos( x ); }
  913. { }
  914. { DESCRIPTION: }
  915. { }
  916. { Range reduction is into intervals of pi/4. The reduction }
  917. { error is nearly eliminated by contriving an extended }
  918. { precision modular arithmetic. }
  919. { }
  920. { Two polynomial approximating functions are employed. }
  921. { Between 0 and pi/4 the cosine is approximated by }
  922. { 1 - x**2 Q(x**2). }
  923. { Between pi/4 and pi/2 the sine is represented as }
  924. { x + x**3 P(x**2). }
  925. {*****************************************************************}
  926. var y, z, zz : Real;
  927. j, sign : Integer;
  928. i : LongInt;
  929. begin
  930. { make argument positive }
  931. sign := 1;
  932. if( d < 0 ) then
  933. d := -d;
  934. { above this value, round towards zero }
  935. if( d > lossth ) then
  936. begin
  937. result := 0.0;
  938. exit;
  939. end;
  940. y := Trunc( d/PIO4 );
  941. z := ldexp( y, -4 );
  942. z := Trunc(z); { integer part of y/8 }
  943. z := y - ldexp( z, 4 ); { y - 16 * (y/16) }
  944. { integer and fractional part modulo one octant }
  945. i := Trunc(z);
  946. if odd( i ) then { map zeros to origin }
  947. begin
  948. inc(i);
  949. y := y + 1.0;
  950. end;
  951. j := i and 07;
  952. if( j > 3) then
  953. begin
  954. dec(j,4);
  955. sign := -sign;
  956. end;
  957. if( j > 1 ) then
  958. sign := -sign;
  959. { Extended precision modular arithmetic }
  960. z := ((d - y * DP1) - y * DP2) - y * DP3;
  961. zz := z * z;
  962. if( (j=1) or (j=2) ) then
  963. { y = z + z * (zz * polevl( zz, sincof, 5 )); }
  964. y := z + z * z * z * polevl( zz, sincof, 5 )
  965. else
  966. y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 );
  967. if(sign < 0) then
  968. y := -y;
  969. result := y ;
  970. end;
  971. {$endif}
  972. {$ifndef FPC_SYSTEM_HAS_ARCTAN}
  973. {$ifdef INTERNCONSTINTF}
  974. function fpc_ArcTan_real(d:Real):Real;compilerproc;
  975. {$else}
  976. function ArcTan(d:Real):Real;[internconst:fpc_in_const_arctan];
  977. {$endif}
  978. {*****************************************************************}
  979. { Inverse circular tangent (arctangent) }
  980. {*****************************************************************}
  981. { }
  982. { SYNOPSIS: }
  983. { }
  984. { double x, y, atan(); }
  985. { }
  986. { y = atan( x ); }
  987. { }
  988. { DESCRIPTION: }
  989. { }
  990. { Returns radian angle between -pi/2 and +pi/2 whose tangent }
  991. { is x. }
  992. { }
  993. { Range reduction is from four intervals into the interval }
  994. { from zero to tan( pi/8 ). The approximant uses a rational }
  995. { function of degree 3/4 of the form x + x**3 P(x)/Q(x). }
  996. {*****************************************************************}
  997. const P : TabCoef = (
  998. -8.40980878064499716001E-1,
  999. -8.83860837023772394279E0,
  1000. -2.18476213081316705724E1,
  1001. -1.48307050340438946993E1, 0, 0, 0);
  1002. Q : TabCoef = (
  1003. 1.54974124675307267552E1,
  1004. 6.27906555762653017263E1,
  1005. 9.22381329856214406485E1,
  1006. 4.44921151021319438465E1, 0, 0, 0);
  1007. { tan( 3*pi/8 ) }
  1008. T3P8 = 2.41421356237309504880;
  1009. { tan( pi/8 ) }
  1010. TP8 = 0.41421356237309504880;
  1011. var y,z : Real;
  1012. Sign : Integer;
  1013. begin
  1014. { make argument positive and save the sign }
  1015. sign := 1;
  1016. if( d < 0.0 ) then
  1017. begin
  1018. sign := -1;
  1019. d := -d;
  1020. end;
  1021. { range reduction }
  1022. if( d > T3P8 ) then
  1023. begin
  1024. y := PIO2;
  1025. d := -( 1.0/d );
  1026. end
  1027. else if( d > TP8 ) then
  1028. begin
  1029. y := PIO4;
  1030. d := (d-1.0)/(d+1.0);
  1031. end
  1032. else
  1033. y := 0.0;
  1034. { rational form in x**2 }
  1035. z := d * d;
  1036. y := y + ( polevl( z, P, 3 ) / p1evl( z, Q, 4 ) ) * z * d + d;
  1037. if( sign < 0 ) then
  1038. y := -y;
  1039. result := y;
  1040. end;
  1041. {$endif}
  1042. {$ifndef FPC_SYSTEM_HAS_FRAC}
  1043. {$ifdef INTERNCONSTINTF}
  1044. function fpc_frac_real(d : Real) : Real;compilerproc;
  1045. {$else}
  1046. function frac(d : Real) : Real;[internconst:fpc_in_const_frac];
  1047. {$endif}
  1048. begin
  1049. result := d - Int(d);
  1050. end;
  1051. {$endif}
  1052. {$ifdef FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
  1053. {$ifndef FPC_SYSTEM_HAS_QWORD_TO_DOUBLE}
  1054. function fpc_qword_to_double(q : qword): double; compilerproc;
  1055. begin
  1056. result:=dword(q and $ffffffff)+dword(q shr 32)*4294967296.0;
  1057. end;
  1058. {$endif FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1059. {$ifndef FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1060. function fpc_int64_to_double(i : int64): double; compilerproc;
  1061. begin
  1062. if i<0 then
  1063. result:=-double(qword(-i))
  1064. else
  1065. result:=qword(i);
  1066. end;
  1067. {$endif FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1068. {$endif FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
  1069. {$ifdef SUPPORT_DOUBLE}
  1070. {****************************************************************************
  1071. Helper routines to support old TP styled reals
  1072. ****************************************************************************}
  1073. {$ifndef FPC_SYSTEM_HAS_REAL2DOUBLE}
  1074. function real2double(r : real48) : double;
  1075. var
  1076. res : array[0..7] of byte;
  1077. exponent : word;
  1078. begin
  1079. { copy mantissa }
  1080. res[0]:=0;
  1081. res[1]:=r[1] shl 5;
  1082. res[2]:=(r[1] shr 3) or (r[2] shl 5);
  1083. res[3]:=(r[2] shr 3) or (r[3] shl 5);
  1084. res[4]:=(r[3] shr 3) or (r[4] shl 5);
  1085. res[5]:=(r[4] shr 3) or (r[5] and $7f) shl 5;
  1086. res[6]:=(r[5] and $7f) shr 3;
  1087. { copy exponent }
  1088. { correct exponent: }
  1089. exponent:=(word(r[0])+(1023-129));
  1090. res[6]:=res[6] or ((exponent and $f) shl 4);
  1091. res[7]:=exponent shr 4;
  1092. { set sign }
  1093. res[7]:=res[7] or (r[5] and $80);
  1094. real2double:=double(res);
  1095. end;
  1096. {$endif FPC_SYSTEM_HAS_REAL2DOUBLE}
  1097. {$endif SUPPORT_DOUBLE}
  1098. {
  1099. $Log: genmath.inc,v $
  1100. Revision 1.32 2005/02/14 17:13:22 peter
  1101. * truncate log
  1102. Revision 1.31 2005/02/08 20:25:28 florian
  1103. - killed power from system unit
  1104. * move operator ** to math unit
  1105. }