genmath.inc 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243
  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. function fpc_abs_real(d:Real):Real;compilerproc; external name 'FPC_ABS_REAL';
  372. {$endif}
  373. {$endif not FPC_SYSTEM_HAS_ABS}
  374. {$ifndef SYSTEM_HAS_FREXP}
  375. function frexp(x:Real; var e:Integer ):Real;
  376. {* frexp() extracts the exponent from x. It returns an integer *}
  377. {* power of two to expnt and the significand between 0.5 and 1 *}
  378. {* to y. Thus x = y * 2**expn. *}
  379. begin
  380. e :=0;
  381. if (abs(x)<0.5) then
  382. While (abs(x)<0.5) do
  383. begin
  384. x := x*2;
  385. Dec(e);
  386. end
  387. else
  388. While (abs(x)>1) do
  389. begin
  390. x := x/2;
  391. Inc(e);
  392. end;
  393. frexp := x;
  394. end;
  395. {$endif not SYSTEM_HAS_FREXP}
  396. {$ifndef SYSTEM_HAS_LDEXP}
  397. function ldexp( x: Real; N: Integer):Real;
  398. {* ldexp() multiplies x by 2**n. *}
  399. var r : Real;
  400. begin
  401. R := 1;
  402. if N>0 then
  403. while N>0 do
  404. begin
  405. R:=R*2;
  406. Dec(N);
  407. end
  408. else
  409. while N<0 do
  410. begin
  411. R:=R/2;
  412. Inc(N);
  413. end;
  414. ldexp := x * R;
  415. end;
  416. {$endif not SYSTEM_HAS_LDEXP}
  417. function polevl(var x:Real; var Coef:TabCoef; N:Integer):Real;
  418. {*****************************************************************}
  419. { Evaluate polynomial }
  420. {*****************************************************************}
  421. { }
  422. { SYNOPSIS: }
  423. { }
  424. { int N; }
  425. { double x, y, coef[N+1], polevl[]; }
  426. { }
  427. { y = polevl( x, coef, N ); }
  428. { }
  429. { DESCRIPTION: }
  430. { }
  431. { Evaluates polynomial of degree N: }
  432. { }
  433. { 2 N }
  434. { y = C + C x + C x +...+ C x }
  435. { 0 1 2 N }
  436. { }
  437. { Coefficients are stored in reverse order: }
  438. { }
  439. { coef[0] = C , ..., coef[N] = C . }
  440. { N 0 }
  441. { }
  442. { The function p1evl() assumes that coef[N] = 1.0 and is }
  443. { omitted from the array. Its calling arguments are }
  444. { otherwise the same as polevl(). }
  445. { }
  446. { SPEED: }
  447. { }
  448. { In the interest of speed, there are no checks for out }
  449. { of bounds arithmetic. This routine is used by most of }
  450. { the functions in the library. Depending on available }
  451. { equipment features, the user may wish to rewrite the }
  452. { program in microcode or assembly language. }
  453. {*****************************************************************}
  454. var ans : Real;
  455. i : Integer;
  456. begin
  457. ans := Coef[0];
  458. for i:=1 to N do
  459. ans := ans * x + Coef[i];
  460. polevl:=ans;
  461. end;
  462. function p1evl(var x:Real; var Coef:TabCoef; N:Integer):Real;
  463. { }
  464. { Evaluate polynomial when coefficient of x is 1.0. }
  465. { Otherwise same as polevl. }
  466. { }
  467. var
  468. ans : Real;
  469. i : Integer;
  470. begin
  471. ans := x + Coef[0];
  472. for i:=1 to N-1 do
  473. ans := ans * x + Coef[i];
  474. p1evl := ans;
  475. end;
  476. {$ifndef FPC_SYSTEM_HAS_SQR}
  477. {$ifdef INTERNCONSTINTF}
  478. function fpc_sqr_real(d : Real) : Real;compilerproc;{$ifdef MATHINLINE}inline;{$endif}
  479. {$else}
  480. function sqr(d : Real) : Real;[internconst:fpc_in_const_sqr];
  481. {$endif}
  482. begin
  483. result := d*d;
  484. end;
  485. {$endif}
  486. {$ifndef FPC_SYSTEM_HAS_PI}
  487. {$ifdef INTERNCONSTINTF}
  488. function fpc_pi_real : Real;compilerproc;{$ifdef MATHINLINE}inline;{$endif}
  489. {$else}
  490. function pi : Real;[internconst:fpc_in_const_pi];
  491. {$endif}
  492. begin
  493. result := 3.1415926535897932385;
  494. end;
  495. {$endif}
  496. {$ifndef FPC_SYSTEM_HAS_SQRT}
  497. {$ifdef INTERNCONSTINTF}
  498. function fpc_sqrt_real(d:Real):Real;compilerproc;
  499. {$else}
  500. function fpc_sqrt_real(d:Real):Real;compilerproc; external name 'FPC_SQRT_REAL';
  501. function sqrt(d:Real):Real;[internconst:fpc_in_const_sqrt];[public, alias: 'FPC_SQRT_REAL'];
  502. {$endif}
  503. {*****************************************************************}
  504. { Square root }
  505. {*****************************************************************}
  506. { }
  507. { SYNOPSIS: }
  508. { }
  509. { double x, y, sqrt(); }
  510. { }
  511. { y = sqrt( x ); }
  512. { }
  513. { DESCRIPTION: }
  514. { }
  515. { Returns the square root of x. }
  516. { }
  517. { Range reduction involves isolating the power of two of the }
  518. { argument and using a polynomial approximation to obtain }
  519. { a rough value for the square root. Then Heron's iteration }
  520. { is used three times to converge to an accurate value. }
  521. {*****************************************************************}
  522. var e : Integer;
  523. w,z : Real;
  524. begin
  525. if( d <= 0.0 ) then
  526. begin
  527. if( d < 0.0 ) then
  528. HandleError(207);
  529. result := 0.0;
  530. end
  531. else
  532. begin
  533. w := d;
  534. { separate exponent and significand }
  535. z := frexp( d, e );
  536. { approximate square root of number between 0.5 and 1 }
  537. { relative error of approximation = 7.47e-3 }
  538. d := 4.173075996388649989089E-1 + 5.9016206709064458299663E-1 * z;
  539. { adjust for odd powers of 2 }
  540. if odd(e) then
  541. d := d*SQRT2;
  542. { re-insert exponent }
  543. d := ldexp( d, (e div 2) );
  544. { Newton iterations: }
  545. d := 0.5*(d + w/d);
  546. d := 0.5*(d + w/d);
  547. d := 0.5*(d + w/d);
  548. d := 0.5*(d + w/d);
  549. d := 0.5*(d + w/d);
  550. d := 0.5*(d + w/d);
  551. result := d;
  552. end;
  553. end;
  554. {$endif}
  555. {$ifndef FPC_SYSTEM_HAS_EXP}
  556. {$ifdef INTERNCONSTINTF}
  557. function fpc_exp_real(d:Real):Real;compilerproc;
  558. {$else}
  559. function Exp(d:Real):Real;[internconst:fpc_in_const_exp];
  560. {$endif}
  561. {*****************************************************************}
  562. { Exponential Function }
  563. {*****************************************************************}
  564. { }
  565. { SYNOPSIS: }
  566. { }
  567. { double x, y, exp(); }
  568. { }
  569. { y = exp( x ); }
  570. { }
  571. { DESCRIPTION: }
  572. { }
  573. { Returns e (2.71828...) raised to the x power. }
  574. { }
  575. { Range reduction is accomplished by separating the argument }
  576. { into an integer k and fraction f such that }
  577. { }
  578. { x k f }
  579. { e = 2 e. }
  580. { }
  581. { A Pade' form of degree 2/3 is used to approximate exp(f)- 1 }
  582. { in the basic range [-0.5 ln 2, 0.5 ln 2]. }
  583. {*****************************************************************}
  584. const P : TabCoef = (
  585. 1.26183092834458542160E-4,
  586. 3.02996887658430129200E-2,
  587. 1.00000000000000000000E0, 0, 0, 0, 0);
  588. Q : TabCoef = (
  589. 3.00227947279887615146E-6,
  590. 2.52453653553222894311E-3,
  591. 2.27266044198352679519E-1,
  592. 2.00000000000000000005E0, 0 ,0 ,0);
  593. C1 = 6.9335937500000000000E-1;
  594. C2 = 2.1219444005469058277E-4;
  595. var n : Integer;
  596. px, qx, xx : Real;
  597. begin
  598. if( d > MAXLOG) then
  599. HandleError(205)
  600. else
  601. if( d < MINLOG ) then
  602. begin
  603. HandleError(205);
  604. end
  605. else
  606. begin
  607. { Express e**x = e**g 2**n }
  608. { = e**g e**( n loge(2) ) }
  609. { = e**( g + n loge(2) ) }
  610. px := d * LOG2E;
  611. qx := Trunc( px + 0.5 ); { Trunc() truncates toward -infinity. }
  612. n := Trunc(qx);
  613. d := d - qx * C1;
  614. d := d + qx * C2;
  615. { rational approximation for exponential }
  616. { of the fractional part: }
  617. { e**x - 1 = 2x P(x**2)/( Q(x**2) - P(x**2) ) }
  618. xx := d * d;
  619. px := d * polevl( xx, P, 2 );
  620. d := px/( polevl( xx, Q, 3 ) - px );
  621. d := ldexp( d, 1 );
  622. d := d + 1.0;
  623. d := ldexp( d, n );
  624. result := d;
  625. end;
  626. end;
  627. {$endif}
  628. {$ifndef FPC_SYSTEM_HAS_ROUND}
  629. {$ifdef INTERNCONSTINTF}
  630. function fpc_round_real(d : Real) : int64;compilerproc;
  631. {$else}
  632. function round(d : Real) : int64;{$ifndef INTERNCONSTINTF}[internconst:fpc_in_const_round];{$endif} external name 'FPC_ROUND';
  633. function fpc_round(d : Real) : int64;[public, alias:'FPC_ROUND'];compilerproc;
  634. {$endif}
  635. var
  636. fr: Real;
  637. tr: Int64;
  638. Begin
  639. fr := abs(Frac(d));
  640. tr := Trunc(d);
  641. if fr > 0.5 then
  642. if d >= 0 then
  643. result:=tr+1
  644. else
  645. result:=tr-1
  646. else
  647. if fr < 0.5 then
  648. result:=tr
  649. else { fr = 0.5 }
  650. { check sign to decide ... }
  651. { as in Turbo Pascal... }
  652. if d >= 0.0 then
  653. result:=tr+1
  654. else
  655. result:=tr;
  656. end;
  657. {$endif}
  658. {$ifdef FPC_CURRENCY_IS_INT64}
  659. function trunc(c : currency) : int64;
  660. type
  661. tmyrec = record
  662. i: int64;
  663. end;
  664. begin
  665. result := int64(tmyrec(c)) div 10000
  666. end;
  667. function trunc(c : comp) : int64;
  668. begin
  669. result := c
  670. end;
  671. function round(c : currency) : int64;
  672. type
  673. tmyrec = record
  674. i: int64;
  675. end;
  676. var
  677. rem, absrem: longint;
  678. begin
  679. { (int64(tmyrec(c))(+/-)5000) div 10000 can overflow }
  680. result := int64(tmyrec(c)) div 10000;
  681. rem := int64(tmyrec(c)) - result * 10000;
  682. absrem := abs(rem);
  683. if (absrem > 5000) or
  684. ((absrem = 5000) and
  685. (rem > 0)) then
  686. if (rem > 0) then
  687. inc(result)
  688. else
  689. dec(result);
  690. end;
  691. function round(c : comp) : int64;
  692. begin
  693. result := c
  694. end;
  695. {$endif FPC_CURRENCY_IS_INT64}
  696. {$ifndef FPC_SYSTEM_HAS_LN}
  697. {$ifdef INTERNCONSTINTF}
  698. function fpc_ln_real(d:Real):Real;compilerproc;
  699. {$else}
  700. function Ln(d:Real):Real;[internconst:fpc_in_const_ln];
  701. {$endif}
  702. {*****************************************************************}
  703. { Natural Logarithm }
  704. {*****************************************************************}
  705. { }
  706. { SYNOPSIS: }
  707. { }
  708. { double x, y, log(); }
  709. { }
  710. { y = ln( x ); }
  711. { }
  712. { DESCRIPTION: }
  713. { }
  714. { Returns the base e (2.718...) logarithm of x. }
  715. { }
  716. { The argument is separated into its exponent and fractional }
  717. { parts. If the exponent is between -1 and +1, the logarithm }
  718. { of the fraction is approximated by }
  719. { }
  720. { log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). }
  721. { }
  722. { Otherwise, setting z = 2(x-1)/x+1), }
  723. { }
  724. { log(x) = z + z**3 P(z)/Q(z). }
  725. { }
  726. {*****************************************************************}
  727. const P : TabCoef = (
  728. { Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
  729. 1/sqrt(2) <= x < sqrt(2) }
  730. 4.58482948458143443514E-5,
  731. 4.98531067254050724270E-1,
  732. 6.56312093769992875930E0,
  733. 2.97877425097986925891E1,
  734. 6.06127134467767258030E1,
  735. 5.67349287391754285487E1,
  736. 1.98892446572874072159E1);
  737. Q : TabCoef = (
  738. 1.50314182634250003249E1,
  739. 8.27410449222435217021E1,
  740. 2.20664384982121929218E2,
  741. 3.07254189979530058263E2,
  742. 2.14955586696422947765E2,
  743. 5.96677339718622216300E1, 0);
  744. { Coefficients for log(x) = z + z**3 P(z)/Q(z),
  745. where z = 2(x-1)/(x+1)
  746. 1/sqrt(2) <= x < sqrt(2) }
  747. R : TabCoef = (
  748. -7.89580278884799154124E-1,
  749. 1.63866645699558079767E1,
  750. -6.41409952958715622951E1, 0, 0, 0, 0);
  751. S : TabCoef = (
  752. -3.56722798256324312549E1,
  753. 3.12093766372244180303E2,
  754. -7.69691943550460008604E2, 0, 0, 0, 0);
  755. var e : Integer;
  756. z, y : Real;
  757. Label Ldone;
  758. begin
  759. if( d <= 0.0 ) then
  760. HandleError(207);
  761. d := frexp( d, e );
  762. { logarithm using log(x) = z + z**3 P(z)/Q(z),
  763. where z = 2(x-1)/x+1) }
  764. if( (e > 2) or (e < -2) ) then
  765. begin
  766. if( d < SQRTH ) then
  767. begin
  768. { 2( 2x-1 )/( 2x+1 ) }
  769. Dec(e, 1);
  770. z := d - 0.5;
  771. y := 0.5 * z + 0.5;
  772. end
  773. else
  774. begin
  775. { 2 (x-1)/(x+1) }
  776. z := d - 0.5;
  777. z := z - 0.5;
  778. y := 0.5 * d + 0.5;
  779. end;
  780. d := z / y;
  781. { /* rational form */ }
  782. z := d*d;
  783. z := d + d * ( z * polevl( z, R, 2 ) / p1evl( z, S, 3 ) );
  784. goto ldone;
  785. end;
  786. { logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) }
  787. if( d < SQRTH ) then
  788. begin
  789. Dec(e, 1);
  790. d := ldexp( d, 1 ) - 1.0; { 2x - 1 }
  791. end
  792. else
  793. d := d - 1.0;
  794. { rational form }
  795. z := d*d;
  796. y := d * ( z * polevl( d, P, 6 ) / p1evl( d, Q, 6 ) );
  797. y := y - ldexp( z, -1 ); { y - 0.5 * z }
  798. z := d + y;
  799. ldone:
  800. { recombine with exponent term }
  801. if( e <> 0 ) then
  802. begin
  803. y := e;
  804. z := z - y * 2.121944400546905827679e-4;
  805. z := z + y * 0.693359375;
  806. end;
  807. result:= z;
  808. end;
  809. {$endif}
  810. {$ifndef FPC_SYSTEM_HAS_SIN}
  811. {$ifdef INTERNCONSTINTF}
  812. function fpc_Sin_real(d:Real):Real;compilerproc;
  813. {$else}
  814. function Sin(d:Real):Real;[internconst:fpc_in_const_sin];
  815. {$endif}
  816. {*****************************************************************}
  817. { Circular Sine }
  818. {*****************************************************************}
  819. { }
  820. { SYNOPSIS: }
  821. { }
  822. { double x, y, sin(); }
  823. { }
  824. { y = sin( x ); }
  825. { }
  826. { DESCRIPTION: }
  827. { }
  828. { Range reduction is into intervals of pi/4. The reduction }
  829. { error is nearly eliminated by contriving an extended }
  830. { precision modular arithmetic. }
  831. { }
  832. { Two polynomial approximating functions are employed. }
  833. { Between 0 and pi/4 the sine is approximated by }
  834. { x + x**3 P(x**2). }
  835. { Between pi/4 and pi/2 the cosine is represented as }
  836. { 1 - x**2 Q(x**2). }
  837. {*****************************************************************}
  838. var y, z, zz : Real;
  839. j, sign : Integer;
  840. begin
  841. { make argument positive but save the sign }
  842. sign := 1;
  843. if( d < 0 ) then
  844. begin
  845. d := -d;
  846. sign := -1;
  847. end;
  848. { above this value, approximate towards 0 }
  849. if( d > lossth ) then
  850. begin
  851. result := 0.0;
  852. exit;
  853. end;
  854. y := Trunc( d/PIO4 ); { integer part of x/PIO4 }
  855. { strip high bits of integer part to prevent integer overflow }
  856. z := ldexp( y, -4 );
  857. z := Trunc(z); { integer part of y/8 }
  858. z := y - ldexp( z, 4 ); { y - 16 * (y/16) }
  859. j := Trunc(z); { convert to integer for tests on the phase angle }
  860. { map zeros to origin }
  861. { typecast is to avoid "can't determine which overloaded function }
  862. { to call" }
  863. if odd( longint(j) ) then
  864. begin
  865. inc(j);
  866. y := y + 1.0;
  867. end;
  868. j := j and 7; { octant modulo 360 degrees }
  869. { reflect in x axis }
  870. if( j > 3) then
  871. begin
  872. sign := -sign;
  873. dec(j, 4);
  874. end;
  875. { Extended precision modular arithmetic }
  876. z := ((d - y * DP1) - y * DP2) - y * DP3;
  877. zz := z * z;
  878. if( (j=1) or (j=2) ) then
  879. y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 )
  880. else
  881. { y = z + z * (zz * polevl( zz, sincof, 5 )); }
  882. y := z + z * z * z * polevl( zz, sincof, 5 );
  883. if(sign < 0) then
  884. y := -y;
  885. result := y;
  886. end;
  887. {$endif}
  888. {$ifndef FPC_SYSTEM_HAS_COS}
  889. {$ifdef INTERNCONSTINTF}
  890. function fpc_Cos_real(d:Real):Real;compilerproc;
  891. {$else}
  892. function Cos(d:Real):Real;[internconst:fpc_in_const_cos];
  893. {$endif}
  894. {*****************************************************************}
  895. { Circular cosine }
  896. {*****************************************************************}
  897. { }
  898. { Circular cosine }
  899. { }
  900. { SYNOPSIS: }
  901. { }
  902. { double x, y, cos(); }
  903. { }
  904. { y = cos( x ); }
  905. { }
  906. { DESCRIPTION: }
  907. { }
  908. { Range reduction is into intervals of pi/4. The reduction }
  909. { error is nearly eliminated by contriving an extended }
  910. { precision modular arithmetic. }
  911. { }
  912. { Two polynomial approximating functions are employed. }
  913. { Between 0 and pi/4 the cosine is approximated by }
  914. { 1 - x**2 Q(x**2). }
  915. { Between pi/4 and pi/2 the sine is represented as }
  916. { x + x**3 P(x**2). }
  917. {*****************************************************************}
  918. var y, z, zz : Real;
  919. j, sign : Integer;
  920. i : LongInt;
  921. begin
  922. { make argument positive }
  923. sign := 1;
  924. if( d < 0 ) then
  925. d := -d;
  926. { above this value, round towards zero }
  927. if( d > lossth ) then
  928. begin
  929. result := 0.0;
  930. exit;
  931. end;
  932. y := Trunc( d/PIO4 );
  933. z := ldexp( y, -4 );
  934. z := Trunc(z); { integer part of y/8 }
  935. z := y - ldexp( z, 4 ); { y - 16 * (y/16) }
  936. { integer and fractional part modulo one octant }
  937. i := Trunc(z);
  938. if odd( i ) then { map zeros to origin }
  939. begin
  940. inc(i);
  941. y := y + 1.0;
  942. end;
  943. j := i and 07;
  944. if( j > 3) then
  945. begin
  946. dec(j,4);
  947. sign := -sign;
  948. end;
  949. if( j > 1 ) then
  950. sign := -sign;
  951. { Extended precision modular arithmetic }
  952. z := ((d - y * DP1) - y * DP2) - y * DP3;
  953. zz := z * z;
  954. if( (j=1) or (j=2) ) then
  955. { y = z + z * (zz * polevl( zz, sincof, 5 )); }
  956. y := z + z * z * z * polevl( zz, sincof, 5 )
  957. else
  958. y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 );
  959. if(sign < 0) then
  960. y := -y;
  961. result := y ;
  962. end;
  963. {$endif}
  964. {$ifndef FPC_SYSTEM_HAS_ARCTAN}
  965. {$ifdef INTERNCONSTINTF}
  966. function fpc_ArcTan_real(d:Real):Real;compilerproc;
  967. {$else}
  968. function ArcTan(d:Real):Real;[internconst:fpc_in_const_arctan];
  969. {$endif}
  970. {*****************************************************************}
  971. { Inverse circular tangent (arctangent) }
  972. {*****************************************************************}
  973. { }
  974. { SYNOPSIS: }
  975. { }
  976. { double x, y, atan(); }
  977. { }
  978. { y = atan( x ); }
  979. { }
  980. { DESCRIPTION: }
  981. { }
  982. { Returns radian angle between -pi/2 and +pi/2 whose tangent }
  983. { is x. }
  984. { }
  985. { Range reduction is from four intervals into the interval }
  986. { from zero to tan( pi/8 ). The approximant uses a rational }
  987. { function of degree 3/4 of the form x + x**3 P(x)/Q(x). }
  988. {*****************************************************************}
  989. const P : TabCoef = (
  990. -8.40980878064499716001E-1,
  991. -8.83860837023772394279E0,
  992. -2.18476213081316705724E1,
  993. -1.48307050340438946993E1, 0, 0, 0);
  994. Q : TabCoef = (
  995. 1.54974124675307267552E1,
  996. 6.27906555762653017263E1,
  997. 9.22381329856214406485E1,
  998. 4.44921151021319438465E1, 0, 0, 0);
  999. { tan( 3*pi/8 ) }
  1000. T3P8 = 2.41421356237309504880;
  1001. { tan( pi/8 ) }
  1002. TP8 = 0.41421356237309504880;
  1003. var y,z : Real;
  1004. Sign : Integer;
  1005. begin
  1006. { make argument positive and save the sign }
  1007. sign := 1;
  1008. if( d < 0.0 ) then
  1009. begin
  1010. sign := -1;
  1011. d := -d;
  1012. end;
  1013. { range reduction }
  1014. if( d > T3P8 ) then
  1015. begin
  1016. y := PIO2;
  1017. d := -( 1.0/d );
  1018. end
  1019. else if( d > TP8 ) then
  1020. begin
  1021. y := PIO4;
  1022. d := (d-1.0)/(d+1.0);
  1023. end
  1024. else
  1025. y := 0.0;
  1026. { rational form in x**2 }
  1027. z := d * d;
  1028. y := y + ( polevl( z, P, 3 ) / p1evl( z, Q, 4 ) ) * z * d + d;
  1029. if( sign < 0 ) then
  1030. y := -y;
  1031. result := y;
  1032. end;
  1033. {$endif}
  1034. {$ifndef FPC_SYSTEM_HAS_FRAC}
  1035. {$ifdef INTERNCONSTINTF}
  1036. function fpc_frac_real(d : Real) : Real;compilerproc;
  1037. {$else}
  1038. function frac(d : Real) : Real;[internconst:fpc_in_const_frac];
  1039. {$endif}
  1040. begin
  1041. result := d - Int(d);
  1042. end;
  1043. {$endif}
  1044. {$ifdef FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
  1045. {$ifndef FPC_SYSTEM_HAS_QWORD_TO_DOUBLE}
  1046. function fpc_qword_to_double(q : qword): double; compilerproc;
  1047. begin
  1048. result:=dword(q and $ffffffff)+dword(q shr 32)*4294967296.0;
  1049. end;
  1050. {$endif FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1051. {$ifndef FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1052. function fpc_int64_to_double(i : int64): double; compilerproc;
  1053. begin
  1054. if i<0 then
  1055. result:=-double(qword(-i))
  1056. else
  1057. result:=qword(i);
  1058. end;
  1059. {$endif FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1060. {$endif FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
  1061. {$ifdef SUPPORT_DOUBLE}
  1062. {****************************************************************************
  1063. Helper routines to support old TP styled reals
  1064. ****************************************************************************}
  1065. {$ifndef FPC_SYSTEM_HAS_REAL2DOUBLE}
  1066. function real2double(r : real48) : double;
  1067. var
  1068. res : array[0..7] of byte;
  1069. exponent : word;
  1070. begin
  1071. { copy mantissa }
  1072. res[0]:=0;
  1073. res[1]:=r[1] shl 5;
  1074. res[2]:=(r[1] shr 3) or (r[2] shl 5);
  1075. res[3]:=(r[2] shr 3) or (r[3] shl 5);
  1076. res[4]:=(r[3] shr 3) or (r[4] shl 5);
  1077. res[5]:=(r[4] shr 3) or (r[5] and $7f) shl 5;
  1078. res[6]:=(r[5] and $7f) shr 3;
  1079. { copy exponent }
  1080. { correct exponent: }
  1081. exponent:=(word(r[0])+(1023-129));
  1082. res[6]:=res[6] or ((exponent and $f) shl 4);
  1083. res[7]:=exponent shr 4;
  1084. { set sign }
  1085. res[7]:=res[7] or (r[5] and $80);
  1086. real2double:=double(res);
  1087. end;
  1088. {$endif FPC_SYSTEM_HAS_REAL2DOUBLE}
  1089. {$endif SUPPORT_DOUBLE}