genmath.inc 40 KB

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