genmath.inc 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246
  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. function fpc_trunc_real(d : ValReal) : int64;compilerproc;
  238. var
  239. {$ifdef cpuarm}
  240. l: longint;
  241. {$endif cpuarm}
  242. f32 : float32;
  243. f64 : float64;
  244. Begin
  245. { in emulation mode the real is equal to a single }
  246. { otherwise in fpu mode, it is equal to a double }
  247. { extended is not supported yet. }
  248. if sizeof(D) > 8 then
  249. HandleError(255);
  250. if sizeof(D)=8 then
  251. begin
  252. move(d,f64,sizeof(f64));
  253. {$ifdef cpuarm}
  254. { the arm fpu has a strange opinion how a double has to be stored }
  255. l:=f64.low;
  256. f64.low:=f64.high;
  257. f64.high:=l;
  258. {$endif cpuarm}
  259. result:=float64_to_int64_round_to_zero(f64);
  260. end
  261. else
  262. begin
  263. move(d,f32,sizeof(f32));
  264. result:=float32_to_int32_round_to_zero(f32);
  265. end;
  266. end;
  267. {$endif}
  268. {$ifndef FPC_SYSTEM_HAS_INT}
  269. {$ifdef SUPPORT_DOUBLE}
  270. { straight Pascal translation of the code for __trunc() in }
  271. { the file sysdeps/libm-ieee754/s_trunc.c of glibc (JM) }
  272. function fpc_int_real(d: ValReal): ValReal;compilerproc;
  273. var
  274. i0, j0: longint;
  275. i1: cardinal;
  276. sx: longint;
  277. f64 : float64;
  278. begin
  279. f64:=float64(d);
  280. {$ifdef cpuarm}
  281. { the arm fpu has a strange opinion how a double has to be stored }
  282. i0:=f64.low;
  283. f64.low:=f64.high;
  284. f64.high:=i0;
  285. {$endif cpuarm}
  286. i0 := f64.high;
  287. i1 := cardinal(f64.low);
  288. sx := i0 and $80000000;
  289. j0 := ((i0 shr 20) and $7ff) - $3ff;
  290. if (j0 < 20) then
  291. begin
  292. if (j0 < 0) then
  293. begin
  294. { the magnitude of the number is < 1 so the result is +-0. }
  295. f64.high := sx;
  296. f64.low := 0;
  297. end
  298. else
  299. begin
  300. f64.high := sx or (i0 and not($fffff shr j0));
  301. f64.low := 0;
  302. end
  303. end
  304. else if (j0 > 51) then
  305. begin
  306. if (j0 = $400) then
  307. { d is inf or NaN }
  308. exit(d + d); { don't know why they do this (JM) }
  309. end
  310. else
  311. begin
  312. f64.high := i0;
  313. f64.low := longint(i1 and not(cardinal($ffffffff) shr (j0 - 20)));
  314. end;
  315. {$ifdef cpuarm}
  316. { the arm fpu has a strange opinion how a double has to be stored }
  317. i0:=f64.low;
  318. f64.low:=f64.high;
  319. f64.high:=i0;
  320. {$endif cpuarm}
  321. result:=double(f64);
  322. end;
  323. {$else SUPPORT_DOUBLE}
  324. function fpc_int_real(d : ValReal) : ValReal;compilerproc;
  325. begin
  326. { this will be correct since real = single in the case of }
  327. { the motorola version of the compiler... }
  328. result:=ValReal(trunc(d));
  329. end;
  330. {$endif SUPPORT_DOUBLE}
  331. {$endif}
  332. {$ifndef FPC_SYSTEM_HAS_ABS}
  333. function fpc_abs_real(d : ValReal) : ValReal;compilerproc;
  334. begin
  335. if (d<0.0) then
  336. result := -d
  337. else
  338. result := d ;
  339. end;
  340. {$endif not FPC_SYSTEM_HAS_ABS}
  341. {$ifndef SYSTEM_HAS_FREXP}
  342. function frexp(x:Real; out e:Integer ):Real;
  343. {* frexp() extracts the exponent from x. It returns an integer *}
  344. {* power of two to expnt and the significand between 0.5 and 1 *}
  345. {* to y. Thus x = y * 2**expn. *}
  346. begin
  347. e :=0;
  348. if (abs(x)<0.5) then
  349. While (abs(x)<0.5) do
  350. begin
  351. x := x*2;
  352. Dec(e);
  353. end
  354. else
  355. While (abs(x)>1) do
  356. begin
  357. x := x/2;
  358. Inc(e);
  359. end;
  360. frexp := x;
  361. end;
  362. {$endif not SYSTEM_HAS_FREXP}
  363. {$ifndef SYSTEM_HAS_LDEXP}
  364. function ldexp( x: Real; N: Integer):Real;
  365. {* ldexp() multiplies x by 2**n. *}
  366. var r : Real;
  367. begin
  368. R := 1;
  369. if N>0 then
  370. while N>0 do
  371. begin
  372. R:=R*2;
  373. Dec(N);
  374. end
  375. else
  376. while N<0 do
  377. begin
  378. R:=R/2;
  379. Inc(N);
  380. end;
  381. ldexp := x * R;
  382. end;
  383. {$endif not SYSTEM_HAS_LDEXP}
  384. function polevl(var x:Real; var Coef:TabCoef; N:Integer):Real;
  385. {*****************************************************************}
  386. { Evaluate polynomial }
  387. {*****************************************************************}
  388. { }
  389. { SYNOPSIS: }
  390. { }
  391. { int N; }
  392. { double x, y, coef[N+1], polevl[]; }
  393. { }
  394. { y = polevl( x, coef, N ); }
  395. { }
  396. { DESCRIPTION: }
  397. { }
  398. { Evaluates polynomial of degree N: }
  399. { }
  400. { 2 N }
  401. { y = C + C x + C x +...+ C x }
  402. { 0 1 2 N }
  403. { }
  404. { Coefficients are stored in reverse order: }
  405. { }
  406. { coef[0] = C , ..., coef[N] = C . }
  407. { N 0 }
  408. { }
  409. { The function p1evl() assumes that coef[N] = 1.0 and is }
  410. { omitted from the array. Its calling arguments are }
  411. { otherwise the same as polevl(). }
  412. { }
  413. { SPEED: }
  414. { }
  415. { In the interest of speed, there are no checks for out }
  416. { of bounds arithmetic. This routine is used by most of }
  417. { the functions in the library. Depending on available }
  418. { equipment features, the user may wish to rewrite the }
  419. { program in microcode or assembly language. }
  420. {*****************************************************************}
  421. var ans : Real;
  422. i : Integer;
  423. begin
  424. ans := Coef[0];
  425. for i:=1 to N do
  426. ans := ans * x + Coef[i];
  427. polevl:=ans;
  428. end;
  429. function p1evl(var x:Real; var Coef:TabCoef; N:Integer):Real;
  430. { }
  431. { Evaluate polynomial when coefficient of x is 1.0. }
  432. { Otherwise same as polevl. }
  433. { }
  434. var
  435. ans : Real;
  436. i : Integer;
  437. begin
  438. ans := x + Coef[0];
  439. for i:=1 to N-1 do
  440. ans := ans * x + Coef[i];
  441. p1evl := ans;
  442. end;
  443. {$ifndef FPC_SYSTEM_HAS_SQR}
  444. function fpc_sqr_real(d : ValReal) : ValReal;compilerproc;{$ifdef MATHINLINE}inline;{$endif}
  445. begin
  446. result := d*d;
  447. end;
  448. {$endif}
  449. {$ifndef FPC_SYSTEM_HAS_PI}
  450. function fpc_pi_real : ValReal;compilerproc;{$ifdef MATHINLINE}inline;{$endif}
  451. begin
  452. result := 3.1415926535897932385;
  453. end;
  454. {$endif}
  455. {$ifndef FPC_SYSTEM_HAS_SQRT}
  456. function fpc_sqrt_real(d:ValReal):ValReal;compilerproc;
  457. {*****************************************************************}
  458. { Square root }
  459. {*****************************************************************}
  460. { }
  461. { SYNOPSIS: }
  462. { }
  463. { double x, y, sqrt(); }
  464. { }
  465. { y = sqrt( x ); }
  466. { }
  467. { DESCRIPTION: }
  468. { }
  469. { Returns the square root of x. }
  470. { }
  471. { Range reduction involves isolating the power of two of the }
  472. { argument and using a polynomial approximation to obtain }
  473. { a rough value for the square root. Then Heron's iteration }
  474. { is used three times to converge to an accurate value. }
  475. {*****************************************************************}
  476. var e : Integer;
  477. w,z : Real;
  478. begin
  479. if( d <= 0.0 ) then
  480. begin
  481. if( d < 0.0 ) then
  482. HandleError(207);
  483. result := 0.0;
  484. end
  485. else
  486. begin
  487. w := d;
  488. { separate exponent and significand }
  489. z := frexp( d, e );
  490. { approximate square root of number between 0.5 and 1 }
  491. { relative error of approximation = 7.47e-3 }
  492. d := 4.173075996388649989089E-1 + 5.9016206709064458299663E-1 * z;
  493. { adjust for odd powers of 2 }
  494. if odd(e) then
  495. d := d*SQRT2;
  496. { re-insert exponent }
  497. d := ldexp( d, (e div 2) );
  498. { Newton iterations: }
  499. d := 0.5*(d + w/d);
  500. d := 0.5*(d + w/d);
  501. d := 0.5*(d + w/d);
  502. d := 0.5*(d + w/d);
  503. d := 0.5*(d + w/d);
  504. d := 0.5*(d + w/d);
  505. result := d;
  506. end;
  507. end;
  508. {$endif}
  509. {$ifndef FPC_SYSTEM_HAS_EXP}
  510. function fpc_exp_real(d: ValReal):ValReal;compilerproc;
  511. {*****************************************************************}
  512. { Exponential Function }
  513. {*****************************************************************}
  514. { }
  515. { SYNOPSIS: }
  516. { }
  517. { double x, y, exp(); }
  518. { }
  519. { y = exp( x ); }
  520. { }
  521. { DESCRIPTION: }
  522. { }
  523. { Returns e (2.71828...) raised to the x power. }
  524. { }
  525. { Range reduction is accomplished by separating the argument }
  526. { into an integer k and fraction f such that }
  527. { }
  528. { x k f }
  529. { e = 2 e. }
  530. { }
  531. { A Pade' form of degree 2/3 is used to approximate exp(f)- 1 }
  532. { in the basic range [-0.5 ln 2, 0.5 ln 2]. }
  533. {*****************************************************************}
  534. const P : TabCoef = (
  535. 1.26183092834458542160E-4,
  536. 3.02996887658430129200E-2,
  537. 1.00000000000000000000E0, 0, 0, 0, 0);
  538. Q : TabCoef = (
  539. 3.00227947279887615146E-6,
  540. 2.52453653553222894311E-3,
  541. 2.27266044198352679519E-1,
  542. 2.00000000000000000005E0, 0 ,0 ,0);
  543. C1 = 6.9335937500000000000E-1;
  544. C2 = 2.1219444005469058277E-4;
  545. var n : Integer;
  546. px, qx, xx : Real;
  547. begin
  548. if( d > MAXLOG) then
  549. HandleError(205)
  550. else
  551. if( d < MINLOG ) then
  552. begin
  553. HandleError(205);
  554. end
  555. else
  556. begin
  557. { Express e**x = e**g 2**n }
  558. { = e**g e**( n loge(2) ) }
  559. { = e**( g + n loge(2) ) }
  560. px := d * LOG2E;
  561. qx := Trunc( px + 0.5 ); { Trunc() truncates toward -infinity. }
  562. n := Trunc(qx);
  563. d := d - qx * C1;
  564. d := d + qx * C2;
  565. { rational approximation for exponential }
  566. { of the fractional part: }
  567. { e**x - 1 = 2x P(x**2)/( Q(x**2) - P(x**2) ) }
  568. xx := d * d;
  569. px := d * polevl( xx, P, 2 );
  570. d := px/( polevl( xx, Q, 3 ) - px );
  571. d := ldexp( d, 1 );
  572. d := d + 1.0;
  573. d := ldexp( d, n );
  574. result := d;
  575. end;
  576. end;
  577. {$endif}
  578. {$ifndef FPC_SYSTEM_HAS_ROUND}
  579. function fpc_round_real(d : ValReal) : int64;compilerproc;
  580. var
  581. fr: Real;
  582. tr: Int64;
  583. Begin
  584. fr := abs(Frac(d));
  585. tr := Trunc(d);
  586. if fr > 0.5 then
  587. if d >= 0 then
  588. result:=tr+1
  589. else
  590. result:=tr-1
  591. else
  592. if fr < 0.5 then
  593. result:=tr
  594. else { fr = 0.5 }
  595. { check sign to decide ... }
  596. { as in Turbo Pascal... }
  597. if d >= 0.0 then
  598. result:=tr+1
  599. else
  600. result:=tr;
  601. end;
  602. {$endif}
  603. {$ifdef FPC_CURRENCY_IS_INT64}
  604. function trunc(c : currency) : int64;
  605. type
  606. tmyrec = record
  607. i: int64;
  608. end;
  609. begin
  610. result := int64(tmyrec(c)) div 10000
  611. end;
  612. function trunc(c : comp) : int64;
  613. begin
  614. result := c
  615. end;
  616. function round(c : currency) : int64;
  617. type
  618. tmyrec = record
  619. i: int64;
  620. end;
  621. var
  622. rem, absrem: longint;
  623. begin
  624. { (int64(tmyrec(c))(+/-)5000) div 10000 can overflow }
  625. result := int64(tmyrec(c)) div 10000;
  626. rem := int64(tmyrec(c)) - result * 10000;
  627. absrem := abs(rem);
  628. if (absrem > 5000) or
  629. ((absrem = 5000) and
  630. (rem > 0)) then
  631. if (rem > 0) then
  632. inc(result)
  633. else
  634. dec(result);
  635. end;
  636. function round(c : comp) : int64;
  637. begin
  638. result := c
  639. end;
  640. {$endif FPC_CURRENCY_IS_INT64}
  641. {$ifndef FPC_SYSTEM_HAS_LN}
  642. function fpc_ln_real(d:ValReal):ValReal;compilerproc;
  643. {*****************************************************************}
  644. { Natural Logarithm }
  645. {*****************************************************************}
  646. { }
  647. { SYNOPSIS: }
  648. { }
  649. { double x, y, log(); }
  650. { }
  651. { y = ln( x ); }
  652. { }
  653. { DESCRIPTION: }
  654. { }
  655. { Returns the base e (2.718...) logarithm of x. }
  656. { }
  657. { The argument is separated into its exponent and fractional }
  658. { parts. If the exponent is between -1 and +1, the logarithm }
  659. { of the fraction is approximated by }
  660. { }
  661. { log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). }
  662. { }
  663. { Otherwise, setting z = 2(x-1)/x+1), }
  664. { }
  665. { log(x) = z + z**3 P(z)/Q(z). }
  666. { }
  667. {*****************************************************************}
  668. const P : TabCoef = (
  669. { Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
  670. 1/sqrt(2) <= x < sqrt(2) }
  671. 4.58482948458143443514E-5,
  672. 4.98531067254050724270E-1,
  673. 6.56312093769992875930E0,
  674. 2.97877425097986925891E1,
  675. 6.06127134467767258030E1,
  676. 5.67349287391754285487E1,
  677. 1.98892446572874072159E1);
  678. Q : TabCoef = (
  679. 1.50314182634250003249E1,
  680. 8.27410449222435217021E1,
  681. 2.20664384982121929218E2,
  682. 3.07254189979530058263E2,
  683. 2.14955586696422947765E2,
  684. 5.96677339718622216300E1, 0);
  685. { Coefficients for log(x) = z + z**3 P(z)/Q(z),
  686. where z = 2(x-1)/(x+1)
  687. 1/sqrt(2) <= x < sqrt(2) }
  688. R : TabCoef = (
  689. -7.89580278884799154124E-1,
  690. 1.63866645699558079767E1,
  691. -6.41409952958715622951E1, 0, 0, 0, 0);
  692. S : TabCoef = (
  693. -3.56722798256324312549E1,
  694. 3.12093766372244180303E2,
  695. -7.69691943550460008604E2, 0, 0, 0, 0);
  696. var e : Integer;
  697. z, y : Real;
  698. Label Ldone;
  699. begin
  700. if( d <= 0.0 ) then
  701. HandleError(207);
  702. d := frexp( d, e );
  703. { logarithm using log(x) = z + z**3 P(z)/Q(z),
  704. where z = 2(x-1)/x+1) }
  705. if( (e > 2) or (e < -2) ) then
  706. begin
  707. if( d < SQRTH ) then
  708. begin
  709. { 2( 2x-1 )/( 2x+1 ) }
  710. Dec(e, 1);
  711. z := d - 0.5;
  712. y := 0.5 * z + 0.5;
  713. end
  714. else
  715. begin
  716. { 2 (x-1)/(x+1) }
  717. z := d - 0.5;
  718. z := z - 0.5;
  719. y := 0.5 * d + 0.5;
  720. end;
  721. d := z / y;
  722. { /* rational form */ }
  723. z := d*d;
  724. z := d + d * ( z * polevl( z, R, 2 ) / p1evl( z, S, 3 ) );
  725. goto ldone;
  726. end;
  727. { logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) }
  728. if( d < SQRTH ) then
  729. begin
  730. Dec(e, 1);
  731. d := ldexp( d, 1 ) - 1.0; { 2x - 1 }
  732. end
  733. else
  734. d := d - 1.0;
  735. { rational form }
  736. z := d*d;
  737. y := d * ( z * polevl( d, P, 6 ) / p1evl( d, Q, 6 ) );
  738. y := y - ldexp( z, -1 ); { y - 0.5 * z }
  739. z := d + y;
  740. ldone:
  741. { recombine with exponent term }
  742. if( e <> 0 ) then
  743. begin
  744. y := e;
  745. z := z - y * 2.121944400546905827679e-4;
  746. z := z + y * 0.693359375;
  747. end;
  748. result:= z;
  749. end;
  750. {$endif}
  751. {$ifndef FPC_SYSTEM_HAS_SIN}
  752. function fpc_Sin_real(d:ValReal):ValReal;compilerproc;
  753. {*****************************************************************}
  754. { Circular Sine }
  755. {*****************************************************************}
  756. { }
  757. { SYNOPSIS: }
  758. { }
  759. { double x, y, sin(); }
  760. { }
  761. { y = sin( x ); }
  762. { }
  763. { DESCRIPTION: }
  764. { }
  765. { Range reduction is into intervals of pi/4. The reduction }
  766. { error is nearly eliminated by contriving an extended }
  767. { precision modular arithmetic. }
  768. { }
  769. { Two polynomial approximating functions are employed. }
  770. { Between 0 and pi/4 the sine is approximated by }
  771. { x + x**3 P(x**2). }
  772. { Between pi/4 and pi/2 the cosine is represented as }
  773. { 1 - x**2 Q(x**2). }
  774. {*****************************************************************}
  775. var y, z, zz : Real;
  776. j, sign : Integer;
  777. begin
  778. { make argument positive but save the sign }
  779. sign := 1;
  780. if( d < 0 ) then
  781. begin
  782. d := -d;
  783. sign := -1;
  784. end;
  785. { above this value, approximate towards 0 }
  786. if( d > lossth ) then
  787. begin
  788. result := 0.0;
  789. exit;
  790. end;
  791. y := Trunc( d/PIO4 ); { integer part of x/PIO4 }
  792. { strip high bits of integer part to prevent integer overflow }
  793. z := ldexp( y, -4 );
  794. z := Trunc(z); { integer part of y/8 }
  795. z := y - ldexp( z, 4 ); { y - 16 * (y/16) }
  796. j := Trunc(z); { convert to integer for tests on the phase angle }
  797. { map zeros to origin }
  798. { typecast is to avoid "can't determine which overloaded function }
  799. { to call" }
  800. if odd( longint(j) ) then
  801. begin
  802. inc(j);
  803. y := y + 1.0;
  804. end;
  805. j := j and 7; { octant modulo 360 degrees }
  806. { reflect in x axis }
  807. if( j > 3) then
  808. begin
  809. sign := -sign;
  810. dec(j, 4);
  811. end;
  812. { Extended precision modular arithmetic }
  813. z := ((d - y * DP1) - y * DP2) - y * DP3;
  814. zz := z * z;
  815. if( (j=1) or (j=2) ) then
  816. y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 )
  817. else
  818. { y = z + z * (zz * polevl( zz, sincof, 5 )); }
  819. y := z + z * z * z * polevl( zz, sincof, 5 );
  820. if(sign < 0) then
  821. y := -y;
  822. result := y;
  823. end;
  824. {$endif}
  825. {$ifndef FPC_SYSTEM_HAS_COS}
  826. function fpc_Cos_real(d:ValReal):ValReal;compilerproc;
  827. {*****************************************************************}
  828. { Circular cosine }
  829. {*****************************************************************}
  830. { }
  831. { Circular cosine }
  832. { }
  833. { SYNOPSIS: }
  834. { }
  835. { double x, y, cos(); }
  836. { }
  837. { y = cos( x ); }
  838. { }
  839. { DESCRIPTION: }
  840. { }
  841. { Range reduction is into intervals of pi/4. The reduction }
  842. { error is nearly eliminated by contriving an extended }
  843. { precision modular arithmetic. }
  844. { }
  845. { Two polynomial approximating functions are employed. }
  846. { Between 0 and pi/4 the cosine is approximated by }
  847. { 1 - x**2 Q(x**2). }
  848. { Between pi/4 and pi/2 the sine is represented as }
  849. { x + x**3 P(x**2). }
  850. {*****************************************************************}
  851. var y, z, zz : Real;
  852. j, sign : Integer;
  853. i : LongInt;
  854. begin
  855. { make argument positive }
  856. sign := 1;
  857. if( d < 0 ) then
  858. d := -d;
  859. { above this value, round towards zero }
  860. if( d > lossth ) then
  861. begin
  862. result := 0.0;
  863. exit;
  864. end;
  865. y := Trunc( d/PIO4 );
  866. z := ldexp( y, -4 );
  867. z := Trunc(z); { integer part of y/8 }
  868. z := y - ldexp( z, 4 ); { y - 16 * (y/16) }
  869. { integer and fractional part modulo one octant }
  870. i := Trunc(z);
  871. if odd( i ) then { map zeros to origin }
  872. begin
  873. inc(i);
  874. y := y + 1.0;
  875. end;
  876. j := i and 07;
  877. if( j > 3) then
  878. begin
  879. dec(j,4);
  880. sign := -sign;
  881. end;
  882. if( j > 1 ) then
  883. sign := -sign;
  884. { Extended precision modular arithmetic }
  885. z := ((d - y * DP1) - y * DP2) - y * DP3;
  886. zz := z * z;
  887. if( (j=1) or (j=2) ) then
  888. { y = z + z * (zz * polevl( zz, sincof, 5 )); }
  889. y := z + z * z * z * polevl( zz, sincof, 5 )
  890. else
  891. y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 );
  892. if(sign < 0) then
  893. y := -y;
  894. result := y ;
  895. end;
  896. {$endif}
  897. {$ifndef FPC_SYSTEM_HAS_ARCTAN}
  898. function fpc_ArcTan_real(d:ValReal):ValReal;compilerproc;
  899. {*****************************************************************}
  900. { Inverse circular tangent (arctangent) }
  901. {*****************************************************************}
  902. { }
  903. { SYNOPSIS: }
  904. { }
  905. { double x, y, atan(); }
  906. { }
  907. { y = atan( x ); }
  908. { }
  909. { DESCRIPTION: }
  910. { }
  911. { Returns radian angle between -pi/2 and +pi/2 whose tangent }
  912. { is x. }
  913. { }
  914. { Range reduction is from four intervals into the interval }
  915. { from zero to tan( pi/8 ). The approximant uses a rational }
  916. { function of degree 3/4 of the form x + x**3 P(x)/Q(x). }
  917. {*****************************************************************}
  918. const P : TabCoef = (
  919. -8.40980878064499716001E-1,
  920. -8.83860837023772394279E0,
  921. -2.18476213081316705724E1,
  922. -1.48307050340438946993E1, 0, 0, 0);
  923. Q : TabCoef = (
  924. 1.54974124675307267552E1,
  925. 6.27906555762653017263E1,
  926. 9.22381329856214406485E1,
  927. 4.44921151021319438465E1, 0, 0, 0);
  928. { tan( 3*pi/8 ) }
  929. T3P8 = 2.41421356237309504880;
  930. { tan( pi/8 ) }
  931. TP8 = 0.41421356237309504880;
  932. var y,z : Real;
  933. Sign : Integer;
  934. begin
  935. { make argument positive and save the sign }
  936. sign := 1;
  937. if( d < 0.0 ) then
  938. begin
  939. sign := -1;
  940. d := -d;
  941. end;
  942. { range reduction }
  943. if( d > T3P8 ) then
  944. begin
  945. y := PIO2;
  946. d := -( 1.0/d );
  947. end
  948. else if( d > TP8 ) then
  949. begin
  950. y := PIO4;
  951. d := (d-1.0)/(d+1.0);
  952. end
  953. else
  954. y := 0.0;
  955. { rational form in x**2 }
  956. z := d * d;
  957. y := y + ( polevl( z, P, 3 ) / p1evl( z, Q, 4 ) ) * z * d + d;
  958. if( sign < 0 ) then
  959. y := -y;
  960. result := y;
  961. end;
  962. {$endif}
  963. {$ifndef FPC_SYSTEM_HAS_FRAC}
  964. function fpc_frac_real(d : ValReal) : ValReal;compilerproc;
  965. begin
  966. result := d - Int(d);
  967. end;
  968. {$endif}
  969. {$ifdef FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
  970. {$ifndef FPC_SYSTEM_HAS_QWORD_TO_DOUBLE}
  971. function fpc_qword_to_double(q : qword): double; compilerproc;
  972. begin
  973. result:=dword(q and $ffffffff)+dword(q shr 32)*4294967296.0;
  974. end;
  975. {$endif FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  976. {$ifndef FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  977. function fpc_int64_to_double(i : int64): double; compilerproc;
  978. begin
  979. if i<0 then
  980. result:=-double(qword(-i))
  981. else
  982. result:=qword(i);
  983. end;
  984. {$endif FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  985. {$endif FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
  986. {$ifdef SUPPORT_DOUBLE}
  987. {****************************************************************************
  988. Helper routines to support old TP styled reals
  989. ****************************************************************************}
  990. {$ifndef FPC_SYSTEM_HAS_REAL2DOUBLE}
  991. function real2double(r : real48) : double;
  992. var
  993. res : array[0..7] of byte;
  994. exponent : word;
  995. begin
  996. { copy mantissa }
  997. res[0]:=0;
  998. res[1]:=r[1] shl 5;
  999. res[2]:=(r[1] shr 3) or (r[2] shl 5);
  1000. res[3]:=(r[2] shr 3) or (r[3] shl 5);
  1001. res[4]:=(r[3] shr 3) or (r[4] shl 5);
  1002. res[5]:=(r[4] shr 3) or (r[5] and $7f) shl 5;
  1003. res[6]:=(r[5] and $7f) shr 3;
  1004. { copy exponent }
  1005. { correct exponent: }
  1006. exponent:=(word(r[0])+(1023-129));
  1007. res[6]:=res[6] or ((exponent and $f) shl 4);
  1008. res[7]:=exponent shr 4;
  1009. { set sign }
  1010. res[7]:=res[7] or (r[5] and $80);
  1011. real2double:=double(res);
  1012. end;
  1013. {$endif FPC_SYSTEM_HAS_REAL2DOUBLE}
  1014. {$endif SUPPORT_DOUBLE}
  1015. {$ifdef SUPPORT_EXTENDED}
  1016. { fast 10^n routine }
  1017. function FPower10(val: Extended; Power: Longint): Extended;
  1018. const
  1019. pow32 : array[0..31] of extended =
  1020. (
  1021. 1e0,1e1,1e2,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,
  1022. 1e11,1e12,1e13,1e14,1e15,1e16,1e17,1e18,1e19,1e20,
  1023. 1e21,1e22,1e23,1e24,1e25,1e26,1e27,1e28,1e29,1e30,
  1024. 1e31
  1025. );
  1026. pow512 : array[0..15] of extended =
  1027. (
  1028. 1,1e32,1e64,1e96,1e128,1e160,1e192,1e224,
  1029. 1e256,1e288,1e320,1e352,1e384,1e416,1e448,
  1030. 1e480
  1031. );
  1032. pow4096 : array[0..9] of extended =
  1033. (1,1e512,1e1024,1e1536,
  1034. 1e2048,1e2560,1e3072,1e3584,
  1035. 1e4096,1e4608
  1036. );
  1037. negpow32 : array[0..31] of extended =
  1038. (
  1039. 1e-0,1e-1,1e-2,1e-3,1e-4,1e-5,1e-6,1e-7,1e-8,1e-9,1e-10,
  1040. 1e-11,1e-12,1e-13,1e-14,1e-15,1e-16,1e-17,1e-18,1e-19,1e-20,
  1041. 1e-21,1e-22,1e-23,1e-24,1e-25,1e-26,1e-27,1e-28,1e-29,1e-30,
  1042. 1e-31
  1043. );
  1044. negpow512 : array[0..15] of extended =
  1045. (
  1046. 0,1e-32,1e-64,1e-96,1e-128,1e-160,1e-192,1e-224,
  1047. 1e-256,1e-288,1e-320,1e-352,1e-384,1e-416,1e-448,
  1048. 1e-480
  1049. );
  1050. negpow4096 : array[0..9] of extended =
  1051. (
  1052. 0,1e-512,1e-1024,1e-1536,
  1053. 1e-2048,1e-2560,1e-3072,1e-3584,
  1054. 1e-4096,1e-4608
  1055. );
  1056. begin
  1057. if Power<0 then
  1058. begin
  1059. Power:=-Power;
  1060. result:=val*negpow32[Power and $1f];
  1061. power:=power shr 5;
  1062. if power<>0 then
  1063. begin
  1064. result:=result*negpow512[Power and $f];
  1065. power:=power shr 4;
  1066. if power<>0 then
  1067. begin
  1068. if power<=9 then
  1069. result:=result*negpow4096[Power]
  1070. else
  1071. result:=1.0/0.0;
  1072. end;
  1073. end;
  1074. end
  1075. else
  1076. begin
  1077. result:=val*pow32[Power and $1f];
  1078. power:=power shr 5;
  1079. if power<>0 then
  1080. begin
  1081. result:=result*pow512[Power and $f];
  1082. power:=power shr 4;
  1083. if power<>0 then
  1084. begin
  1085. if power<=9 then
  1086. result:=result*pow4096[Power]
  1087. else
  1088. result:=1.0/0.0;
  1089. end;
  1090. end;
  1091. end;
  1092. end;
  1093. {$endif SUPPORT_EXTENDED}