genmath.inc 41 KB

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