genmath.inc 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2007 by Several contributors
  4. Generic mathematical 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. {$if not defined(FPC_SYSTEM_HAS_SIN) or not defined(FPC_SYSTEM_HAS_COS)}
  68. const sincof : TabCoef = (
  69. 1.58962301576546568060E-10,
  70. -2.50507477628578072866E-8,
  71. 2.75573136213857245213E-6,
  72. -1.98412698295895385996E-4,
  73. 8.33333333332211858878E-3,
  74. -1.66666666666666307295E-1, 0);
  75. coscof : TabCoef = (
  76. -1.13585365213876817300E-11,
  77. 2.08757008419747316778E-9,
  78. -2.75573141792967388112E-7,
  79. 2.48015872888517045348E-5,
  80. -1.38888888888730564116E-3,
  81. 4.16666666666665929218E-2, 0);
  82. {$endif}
  83. {*
  84. -------------------------------------------------------------------------------
  85. Raises the exceptions specified by `flags'. Floating-point traps can be
  86. defined here if desired. It is currently not possible for such a trap
  87. to substitute a result value. If traps are not implemented, this routine
  88. should be simply `softfloat_exception_flags |= flags;'.
  89. -------------------------------------------------------------------------------
  90. *}
  91. procedure float_raise(i: shortint);
  92. var
  93. pflags: pbyte;
  94. unmasked_flags: byte;
  95. Begin
  96. { taking address of threadvar produces somewhat more compact code }
  97. pflags := @softfloat_exception_flags;
  98. pflags^ := pflags^ or i;
  99. unmasked_flags := pflags^ and (not softfloat_exception_mask);
  100. if (unmasked_flags and float_flag_invalid) <> 0 then
  101. HandleError(207)
  102. else
  103. if (unmasked_flags and float_flag_divbyzero) <> 0 then
  104. HandleError(200)
  105. else
  106. if (unmasked_flags and float_flag_overflow) <> 0 then
  107. HandleError(205)
  108. else
  109. if (unmasked_flags and float_flag_underflow) <> 0 then
  110. HandleError(206)
  111. else
  112. if (unmasked_flags and float_flag_inexact) <> 0 then
  113. HandleError(207);
  114. end;
  115. {$ifndef FPC_SYSTEM_HAS_TRUNC}
  116. {$ifndef FPC_SYSTEM_HAS_float32}
  117. type
  118. float32 = longint;
  119. {$endif FPC_SYSTEM_HAS_float32}
  120. {$ifndef FPC_SYSTEM_HAS_flag}
  121. type
  122. flag = byte;
  123. {$endif FPC_SYSTEM_HAS_flag}
  124. {$ifndef FPC_SYSTEM_HAS_extractFloat64Frac0}
  125. Function extractFloat64Frac0(const a: float64): longint;
  126. Begin
  127. extractFloat64Frac0 := a.high and $000FFFFF;
  128. End;
  129. {$endif not FPC_SYSTEM_HAS_extractFloat64Frac0}
  130. {$ifndef FPC_SYSTEM_HAS_extractFloat64Frac1}
  131. Function extractFloat64Frac1(const a: float64): longint;
  132. Begin
  133. extractFloat64Frac1 := a.low;
  134. End;
  135. {$endif not FPC_SYSTEM_HAS_extractFloat64Frac1}
  136. {$ifndef FPC_SYSTEM_HAS_extractFloat64Exp}
  137. Function extractFloat64Exp(const a: float64): smallint;
  138. Begin
  139. extractFloat64Exp:= ( a.high shr 20 ) AND $7FF;
  140. End;
  141. {$endif not FPC_SYSTEM_HAS_extractFloat64Exp}
  142. {$ifndef FPC_SYSTEM_HAS_extractFloat64Frac}
  143. Function extractFloat64Frac(const a: float64): int64;
  144. Begin
  145. extractFloat64Frac:=int64(a) and $000FFFFFFFFFFFFF;
  146. End;
  147. {$endif not FPC_SYSTEM_HAS_extractFloat64Frac}
  148. {$ifndef FPC_SYSTEM_HAS_extractFloat64Sign}
  149. Function extractFloat64Sign(const a: float64) : flag;
  150. Begin
  151. extractFloat64Sign := a.high shr 31;
  152. End;
  153. {$endif not FPC_SYSTEM_HAS_extractFloat64Sign}
  154. Procedure shortShift64Left(a0:longint; a1:longint; count:smallint; VAR z0Ptr:longint; VAR z1Ptr:longint );
  155. Begin
  156. z1Ptr := a1 shl count;
  157. if count = 0 then
  158. z0Ptr := a0
  159. else
  160. z0Ptr := ( a0 shl count ) OR ( a1 shr ( ( - count ) AND 31 ) );
  161. End;
  162. function float64_to_int32_round_to_zero(a: float64 ): longint;
  163. Var
  164. aSign: flag;
  165. aExp, shiftCount: smallint;
  166. aSig0, aSig1, absZ, aSigExtra: longint;
  167. z: longint;
  168. label
  169. invalid;
  170. Begin
  171. aSig1 := extractFloat64Frac1( a );
  172. aSig0 := extractFloat64Frac0( a );
  173. aExp := extractFloat64Exp( a );
  174. aSign := extractFloat64Sign( a );
  175. shiftCount := aExp - $413;
  176. if 0<=shiftCount then
  177. Begin
  178. if (aExp=$7FF) and ((aSig0 or aSig1)<>0) then
  179. goto invalid;
  180. shortShift64Left(aSig0 OR $00100000, aSig1, shiftCount, absZ, aSigExtra );
  181. End
  182. else
  183. Begin
  184. if aExp<$3FF then
  185. begin
  186. float64_to_int32_round_to_zero := 0;
  187. exit;
  188. end;
  189. aSig0 := aSig0 or $00100000;
  190. aSigExtra := ( aSig0 shl ( shiftCount and 31 ) ) OR aSig1;
  191. absZ := aSig0 shr ( - shiftCount );
  192. End;
  193. if aSign<>0 then
  194. z:=-absZ
  195. else
  196. z:=absZ;
  197. if ((aSign<>0) xor (z<0)) AND (z<>0) then
  198. begin
  199. invalid:
  200. float_raise(float_flag_invalid);
  201. if (aSign <> 0) then
  202. float64_to_int32_round_to_zero:=longint($80000000)
  203. else
  204. float64_to_int32_round_to_zero:=$7FFFFFFF;
  205. exit;
  206. end;
  207. if ( aSigExtra <> 0) then
  208. float_raise(float_flag_inexact);
  209. float64_to_int32_round_to_zero := z;
  210. End;
  211. function genmath_float64_to_int64_round_to_zero(a : float64) : int64;
  212. var
  213. aSign : flag;
  214. aExp, shiftCount : smallint;
  215. aSig : int64;
  216. z : int64;
  217. begin
  218. aSig:=extractFloat64Frac(a);
  219. aExp:=extractFloat64Exp(a);
  220. aSign:=extractFloat64Sign(a);
  221. if aExp<>0 then
  222. aSig:=aSig or $0010000000000000;
  223. shiftCount:= aExp-$433;
  224. if 0<=shiftCount then
  225. begin
  226. if aExp>=$43e then
  227. begin
  228. if int64(a)<>$C3E0000000000000 then
  229. begin
  230. float_raise(float_flag_invalid);
  231. if (aSign=0) or ((aExp=$7FF) and
  232. (aSig<>$0010000000000000 )) then
  233. begin
  234. result:=$7FFFFFFFFFFFFFFF;
  235. exit;
  236. end;
  237. end;
  238. result:=$8000000000000000;
  239. exit;
  240. end;
  241. z:=aSig shl shiftCount;
  242. end
  243. else
  244. begin
  245. if aExp<$3fe then
  246. begin
  247. result:=0;
  248. exit;
  249. end;
  250. z:=aSig shr -shiftCount;
  251. {
  252. if (aSig shl (shiftCount and 63))<>0 then
  253. float_exception_flags |= float_flag_inexact;
  254. }
  255. end;
  256. if aSign<>0 then
  257. z:=-z;
  258. result:=z;
  259. end;
  260. Function float32_to_int32_round_to_zero( a: Float32 ): longint;
  261. Var
  262. aSign : flag;
  263. aExp, shiftCount : smallint;
  264. aSig : longint;
  265. z : longint;
  266. Begin
  267. aSig := a and $007FFFFF;
  268. aExp := (a shr 23) and $FF;
  269. aSign := a shr 31;
  270. shiftCount := aExp - $9E;
  271. if ( 0 <= shiftCount ) then
  272. Begin
  273. if ( a <> Float32($CF000000) ) then
  274. Begin
  275. float_raise( float_flag_invalid );
  276. if ( (aSign=0) or ( ( aExp = $FF ) and (aSig<>0) ) ) then
  277. Begin
  278. float32_to_int32_round_to_zero:=$7fffffff;
  279. exit;
  280. end;
  281. End;
  282. float32_to_int32_round_to_zero:=longint($80000000);
  283. exit;
  284. End
  285. else
  286. if ( aExp <= $7E ) then
  287. Begin
  288. float32_to_int32_round_to_zero := 0;
  289. exit;
  290. End;
  291. aSig := ( aSig or $00800000 ) shl 8;
  292. z := aSig shr ( - shiftCount );
  293. if ( aSign<>0 ) then z := - z;
  294. float32_to_int32_round_to_zero := z;
  295. End;
  296. function fpc_trunc_real(d : ValReal) : int64;compilerproc;
  297. var
  298. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  299. l: longint;
  300. {$endif FPC_DOUBLE_HILO_SWAPPED}
  301. f32 : float32;
  302. f64 : float64;
  303. Begin
  304. { in emulation mode the real is equal to a single }
  305. { otherwise in fpu mode, it is equal to a double }
  306. { extended is not supported yet. }
  307. if sizeof(D) > 8 then
  308. HandleError(255);
  309. if sizeof(D)=8 then
  310. begin
  311. move(d,f64,sizeof(f64));
  312. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  313. { the arm fpu has a strange opinion how a double has to be stored }
  314. l:=f64.low;
  315. f64.low:=f64.high;
  316. f64.high:=l;
  317. {$endif FPC_DOUBLE_HILO_SWAPPED}
  318. result:=genmath_float64_to_int64_round_to_zero(f64);
  319. end
  320. else
  321. begin
  322. move(d,f32,sizeof(f32));
  323. result:=float32_to_int32_round_to_zero(f32);
  324. end;
  325. end;
  326. {$endif not FPC_SYSTEM_HAS_TRUNC}
  327. {$ifndef FPC_SYSTEM_HAS_INT}
  328. {$ifdef SUPPORT_DOUBLE}
  329. { straight Pascal translation of the code for __trunc() in }
  330. { the file sysdeps/libm-ieee754/s_trunc.c of glibc (JM) }
  331. function fpc_int_real(d: ValReal): ValReal;compilerproc;
  332. var
  333. i0, j0: longint;
  334. i1: cardinal;
  335. sx: longint;
  336. f64 : float64;
  337. begin
  338. f64:=float64(d);
  339. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  340. { the arm fpu has a strange opinion how a double has to be stored }
  341. i0:=f64.low;
  342. f64.low:=f64.high;
  343. f64.high:=i0;
  344. {$endif FPC_DOUBLE_HILO_SWAPPED}
  345. i0 := f64.high;
  346. i1 := cardinal(f64.low);
  347. sx := i0 and $80000000;
  348. j0 := ((i0 shr 20) and $7ff) - $3ff;
  349. if (j0 < 20) then
  350. begin
  351. if (j0 < 0) then
  352. begin
  353. { the magnitude of the number is < 1 so the result is +-0. }
  354. f64.high := sx;
  355. f64.low := 0;
  356. end
  357. else
  358. begin
  359. f64.high := sx or (i0 and not($fffff shr j0));
  360. f64.low := 0;
  361. end
  362. end
  363. else if (j0 > 51) then
  364. begin
  365. if (j0 = $400) then
  366. { d is inf or NaN }
  367. exit(d + d); { don't know why they do this (JM) }
  368. end
  369. else
  370. begin
  371. f64.high := i0;
  372. f64.low := longint(i1 and not(cardinal($ffffffff) shr (j0 - 20)));
  373. end;
  374. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  375. { the arm fpu has a strange opinion how a double has to be stored }
  376. i0:=f64.low;
  377. f64.low:=f64.high;
  378. f64.high:=i0;
  379. {$endif FPC_DOUBLE_HILO_SWAPPED}
  380. result:=double(f64);
  381. end;
  382. {$else SUPPORT_DOUBLE}
  383. function fpc_int_real(d : ValReal) : ValReal;compilerproc;
  384. begin
  385. { this will be correct since real = single in the case of }
  386. { the motorola version of the compiler... }
  387. result:=ValReal(trunc(d));
  388. end;
  389. {$endif SUPPORT_DOUBLE}
  390. {$endif not FPC_SYSTEM_HAS_INT}
  391. {$ifndef FPC_SYSTEM_HAS_ABS}
  392. function fpc_abs_real(d : ValReal) : ValReal;compilerproc;
  393. begin
  394. if (d<0.0) then
  395. result := -d
  396. else
  397. result := d ;
  398. end;
  399. {$endif not FPC_SYSTEM_HAS_ABS}
  400. {$ifndef SYSTEM_HAS_FREXP}
  401. function frexp(x:Real; out e:Integer ):Real;
  402. {* frexp() extracts the exponent from x. It returns an integer *}
  403. {* power of two to expnt and the significand between 0.5 and 1 *}
  404. {* to y. Thus x = y * 2**expn. *}
  405. begin
  406. e :=0;
  407. if (abs(x)<0.5) then
  408. While (abs(x)<0.5) do
  409. begin
  410. x := x*2;
  411. Dec(e);
  412. end
  413. else
  414. While (abs(x)>1) do
  415. begin
  416. x := x/2;
  417. Inc(e);
  418. end;
  419. frexp := x;
  420. end;
  421. {$endif not SYSTEM_HAS_FREXP}
  422. {$ifndef SYSTEM_HAS_LDEXP}
  423. function ldexp( x: Real; N: Integer):Real;
  424. {* ldexp() multiplies x by 2**n. *}
  425. var r : Real;
  426. begin
  427. R := 1;
  428. if N>0 then
  429. while N>0 do
  430. begin
  431. R:=R*2;
  432. Dec(N);
  433. end
  434. else
  435. while N<0 do
  436. begin
  437. R:=R/2;
  438. Inc(N);
  439. end;
  440. ldexp := x * R;
  441. end;
  442. {$endif not SYSTEM_HAS_LDEXP}
  443. function polevl(var x:Real; var Coef:TabCoef; N:Integer):Real;
  444. {*****************************************************************}
  445. { Evaluate polynomial }
  446. {*****************************************************************}
  447. { }
  448. { SYNOPSIS: }
  449. { }
  450. { int N; }
  451. { double x, y, coef[N+1], polevl[]; }
  452. { }
  453. { y = polevl( x, coef, N ); }
  454. { }
  455. { DESCRIPTION: }
  456. { }
  457. { Evaluates polynomial of degree N: }
  458. { }
  459. { 2 N }
  460. { y = C + C x + C x +...+ C x }
  461. { 0 1 2 N }
  462. { }
  463. { Coefficients are stored in reverse order: }
  464. { }
  465. { coef[0] = C , ..., coef[N] = C . }
  466. { N 0 }
  467. { }
  468. { The function p1evl() assumes that coef[N] = 1.0 and is }
  469. { omitted from the array. Its calling arguments are }
  470. { otherwise the same as polevl(). }
  471. { }
  472. { SPEED: }
  473. { }
  474. { In the interest of speed, there are no checks for out }
  475. { of bounds arithmetic. This routine is used by most of }
  476. { the functions in the library. Depending on available }
  477. { equipment features, the user may wish to rewrite the }
  478. { program in microcode or assembly language. }
  479. {*****************************************************************}
  480. var ans : Real;
  481. i : Integer;
  482. begin
  483. ans := Coef[0];
  484. for i:=1 to N do
  485. ans := ans * x + Coef[i];
  486. polevl:=ans;
  487. end;
  488. function p1evl(var x:Real; var Coef:TabCoef; N:Integer):Real;
  489. { }
  490. { Evaluate polynomial when coefficient of x is 1.0. }
  491. { Otherwise same as polevl. }
  492. { }
  493. var
  494. ans : Real;
  495. i : Integer;
  496. begin
  497. ans := x + Coef[0];
  498. for i:=1 to N-1 do
  499. ans := ans * x + Coef[i];
  500. p1evl := ans;
  501. end;
  502. {$ifndef FPC_SYSTEM_HAS_SQR}
  503. function fpc_sqr_real(d : ValReal) : ValReal;compilerproc;{$ifdef MATHINLINE}inline;{$endif}
  504. begin
  505. result := d*d;
  506. end;
  507. {$endif}
  508. {$ifndef FPC_SYSTEM_HAS_PI}
  509. function fpc_pi_real : ValReal;compilerproc;{$ifdef MATHINLINE}inline;{$endif}
  510. begin
  511. result := 3.1415926535897932385;
  512. end;
  513. {$endif}
  514. {$ifndef FPC_SYSTEM_HAS_SQRT}
  515. function fpc_sqrt_real(d:ValReal):ValReal;compilerproc;
  516. {*****************************************************************}
  517. { Square root }
  518. {*****************************************************************}
  519. { }
  520. { SYNOPSIS: }
  521. { }
  522. { double x, y, sqrt(); }
  523. { }
  524. { y = sqrt( x ); }
  525. { }
  526. { DESCRIPTION: }
  527. { }
  528. { Returns the square root of x. }
  529. { }
  530. { Range reduction involves isolating the power of two of the }
  531. { argument and using a polynomial approximation to obtain }
  532. { a rough value for the square root. Then Heron's iteration }
  533. { is used three times to converge to an accurate value. }
  534. {*****************************************************************}
  535. var e : Integer;
  536. w,z : Real;
  537. begin
  538. if( d <= 0.0 ) then
  539. begin
  540. if d < 0.0 then begin
  541. float_raise(float_flag_invalid);
  542. d := 0/0;
  543. end;
  544. result := 0.0;
  545. end
  546. else
  547. begin
  548. w := d;
  549. { separate exponent and significand }
  550. z := frexp( d, e );
  551. { approximate square root of number between 0.5 and 1 }
  552. { relative error of approximation = 7.47e-3 }
  553. d := 4.173075996388649989089E-1 + 5.9016206709064458299663E-1 * z;
  554. { adjust for odd powers of 2 }
  555. if odd(e) then
  556. d := d*SQRT2;
  557. { re-insert exponent }
  558. d := ldexp( d, (e div 2) );
  559. { Newton iterations: }
  560. d := 0.5*(d + w/d);
  561. d := 0.5*(d + w/d);
  562. d := 0.5*(d + w/d);
  563. d := 0.5*(d + w/d);
  564. d := 0.5*(d + w/d);
  565. d := 0.5*(d + w/d);
  566. result := d;
  567. end;
  568. end;
  569. {$endif}
  570. {$ifndef FPC_SYSTEM_HAS_EXP}
  571. {$ifdef SUPPORT_DOUBLE}
  572. {
  573. This code was translated from uclib code, the original code
  574. had the following copyright notice:
  575. *
  576. * ====================================================
  577. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  578. *
  579. * Developed at SunPro, a Sun Microsystems, Inc. business.
  580. * Permission to use, copy, modify, and distribute this
  581. * software is freely granted, provided that this notice
  582. * is preserved.
  583. * ====================================================
  584. *}
  585. {*
  586. * Returns the exponential of x.
  587. *
  588. * Method
  589. * 1. Argument reduction:
  590. * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
  591. * Given x, find r and integer k such that
  592. *
  593. * x = k*ln2 + r, |r| <= 0.5*ln2.
  594. *
  595. * Here r will be represented as r = hi-lo for better
  596. * accuracy.
  597. *
  598. * 2. Approximation of exp(r) by a special rational function on
  599. * the interval [0,0.34658]:
  600. * Write
  601. * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
  602. * We use a special Reme algorithm on [0,0.34658] to generate
  603. * a polynomial of degree 5 to approximate R. The maximum error
  604. * of this polynomial approximation is bounded by 2**-59. In
  605. * other words,
  606. * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
  607. * (where z=r*r, and the values of P1 to P5 are listed below)
  608. * and
  609. * | 5 | -59
  610. * | 2.0+P1*z+...+P5*z - R(z) | <= 2
  611. * | |
  612. * The computation of exp(r) thus becomes
  613. * 2*r
  614. * exp(r) = 1 + -------
  615. * R - r
  616. * r*R1(r)
  617. * = 1 + r + ----------- (for better accuracy)
  618. * 2 - R1(r)
  619. * where
  620. 2 4 10
  621. * R1(r) = r - (P1*r + P2*r + ... + P5*r ).
  622. *
  623. * 3. Scale back to obtain exp(x):
  624. * From step 1, we have
  625. * exp(x) = 2^k * exp(r)
  626. *
  627. * Special cases:
  628. * exp(INF) is INF, exp(NaN) is NaN;
  629. * exp(-INF) is 0, and
  630. * for finite argument, only exp(0)=1 is exact.
  631. *
  632. * Accuracy:
  633. * according to an error analysis, the error is always less than
  634. * 1 ulp (unit in the last place).
  635. *
  636. * Misc. info.
  637. * For IEEE double
  638. * if x > 7.09782712893383973096e+02 then exp(x) overflow
  639. * if x < -7.45133219101941108420e+02 then exp(x) underflow
  640. *
  641. * Constants:
  642. * The hexadecimal values are the intended ones for the following
  643. * constants. The decimal values may be used, provided that the
  644. * compiler will convert from decimal to binary accurately enough
  645. * to produce the hexadecimal values shown.
  646. *
  647. }
  648. function fpc_exp_real(d: ValReal):ValReal;compilerproc;
  649. const
  650. one: double = 1.0;
  651. halF : array[0..1] of double = (0.5,-0.5);
  652. huge: double = 1.0e+300;
  653. twom1000: double = 9.33263618503218878990e-302; { 2**-1000=0x01700000,0}
  654. o_threshold: double = 7.09782712893383973096e+02; { 0x40862E42, 0xFEFA39EF }
  655. u_threshold: double = -7.45133219101941108420e+02; { 0xc0874910, 0xD52D3051 }
  656. ln2HI : array[0..1] of double = ( 6.93147180369123816490e-01, { 0x3fe62e42, 0xfee00000 }
  657. -6.93147180369123816490e-01); { 0xbfe62e42, 0xfee00000 }
  658. ln2LO : array[0..1] of double = (1.90821492927058770002e-10, { 0x3dea39ef, 0x35793c76 }
  659. -1.90821492927058770002e-10); { 0xbdea39ef, 0x35793c76 }
  660. invln2: double = 1.44269504088896338700e+00; { 0x3ff71547, 0x652b82fe }
  661. P1: double = 1.66666666666666019037e-01; { 0x3FC55555, 0x5555553E }
  662. P2: double = -2.77777777770155933842e-03; { 0xBF66C16C, 0x16BEBD93 }
  663. P3: double = 6.61375632143793436117e-05; { 0x3F11566A, 0xAF25DE2C }
  664. P4: double = -1.65339022054652515390e-06; { 0xBEBBBD41, 0xC5D26BF1 }
  665. P5: double = 4.13813679705723846039e-08; { 0x3E663769, 0x72BEA4D0 }
  666. var
  667. c,hi,lo,t,y : double;
  668. k,xsb : longint;
  669. hx,hy,lx : dword;
  670. begin
  671. hi:=0.0;
  672. lo:=0.0;
  673. k:=0;
  674. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  675. hx:=float64(d).low;
  676. {$else}
  677. hx:=float64(d).high;
  678. {$endif FPC_DOUBLE_HILO_SWAPPED}
  679. xsb := (hx shr 31) and 1; { sign bit of d }
  680. hx := hx and $7fffffff; { high word of |d| }
  681. { filter out non-finite argument }
  682. if hx >= $40862E42 then
  683. begin { if |d|>=709.78... }
  684. if hx >= $7ff00000 then
  685. begin
  686. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  687. lx:=float64(d).high;
  688. {$else}
  689. lx:=float64(d).low;
  690. {$endif FPC_DOUBLE_HILO_SWAPPED}
  691. if ((hx and $fffff) or lx)<>0 then
  692. begin
  693. result:=d+d; { NaN }
  694. exit;
  695. end
  696. else
  697. begin
  698. if xsb=0 then
  699. result:=d
  700. else
  701. result:=0.0; { exp(+-inf)=(inf,0) }
  702. exit;
  703. end;
  704. end;
  705. if d > o_threshold then begin
  706. result:=huge*huge; { overflow }
  707. exit;
  708. end;
  709. if d < u_threshold then begin
  710. result:=twom1000*twom1000; { underflow }
  711. exit;
  712. end;
  713. end;
  714. { argument reduction }
  715. if hx > $3fd62e42 then
  716. begin { if |d| > 0.5 ln2 }
  717. if hx < $3FF0A2B2 then { and |d| < 1.5 ln2 }
  718. begin
  719. hi := d-ln2HI[xsb];
  720. lo:=ln2LO[xsb];
  721. k := 1-xsb-xsb;
  722. end
  723. else
  724. begin
  725. k := trunc(invln2*d+halF[xsb]);
  726. t := k;
  727. hi := d - t*ln2HI[0]; { t*ln2HI is exact here }
  728. lo := t*ln2LO[0];
  729. end;
  730. d := hi - lo;
  731. end
  732. else if hx < $3e300000 then
  733. begin { when |d|<2**-28 }
  734. if huge+d>one then
  735. begin
  736. result:=one+d;{ trigger inexact }
  737. exit;
  738. end;
  739. end
  740. else
  741. k := 0;
  742. { d is now in primary range }
  743. t:=d*d;
  744. c:=d - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
  745. if k=0 then
  746. begin
  747. result:=one-((d*c)/(c-2.0)-d);
  748. exit;
  749. end
  750. else
  751. y := one-((lo-(d*c)/(2.0-c))-hi);
  752. if k >= -1021 then
  753. begin
  754. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  755. hy:=float64(y).low;
  756. float64(y).low:=longint(hy)+(k shl 20); { add k to y's exponent }
  757. {$else}
  758. hy:=float64(y).high;
  759. float64(y).high:=longint(hy)+(k shl 20); { add k to y's exponent }
  760. {$endif FPC_DOUBLE_HILO_SWAPPED}
  761. result:=y;
  762. end
  763. else
  764. begin
  765. {$ifdef FPC_DOUBLE_HILO_SWAPPED}
  766. hy:=float64(y).low;
  767. float64(y).low:=longint(hy)+((k+1000) shl 20); { add k to y's exponent }
  768. {$else}
  769. hy:=float64(y).high;
  770. float64(y).high:=longint(hy)+((k+1000) shl 20); { add k to y's exponent }
  771. {$endif FPC_DOUBLE_HILO_SWAPPED}
  772. result:=y*twom1000;
  773. end;
  774. end;
  775. {$else SUPPORT_DOUBLE}
  776. function fpc_exp_real(d: ValReal):ValReal;compilerproc;
  777. {*****************************************************************}
  778. { Exponential Function }
  779. {*****************************************************************}
  780. { }
  781. { SYNOPSIS: }
  782. { }
  783. { double x, y, exp(); }
  784. { }
  785. { y = exp( x ); }
  786. { }
  787. { DESCRIPTION: }
  788. { }
  789. { Returns e (2.71828...) raised to the x power. }
  790. { }
  791. { Range reduction is accomplished by separating the argument }
  792. { into an integer k and fraction f such that }
  793. { }
  794. { x k f }
  795. { e = 2 e. }
  796. { }
  797. { A Pade' form of degree 2/3 is used to approximate exp(f)- 1 }
  798. { in the basic range [-0.5 ln 2, 0.5 ln 2]. }
  799. {*****************************************************************}
  800. const P : TabCoef = (
  801. 1.26183092834458542160E-4,
  802. 3.02996887658430129200E-2,
  803. 1.00000000000000000000E0, 0, 0, 0, 0);
  804. Q : TabCoef = (
  805. 3.00227947279887615146E-6,
  806. 2.52453653553222894311E-3,
  807. 2.27266044198352679519E-1,
  808. 2.00000000000000000005E0, 0 ,0 ,0);
  809. C1 = 6.9335937500000000000E-1;
  810. C2 = 2.1219444005469058277E-4;
  811. var n : Integer;
  812. px, qx, xx : Real;
  813. begin
  814. if( d > MAXLOG) then
  815. float_raise(float_flag_overflow)
  816. else
  817. if( d < MINLOG ) then
  818. begin
  819. float_raise(float_flag_underflow);
  820. result:=0; { Result if underflow masked }
  821. end
  822. else
  823. begin
  824. { Express e**x = e**g 2**n }
  825. { = e**g e**( n loge(2) ) }
  826. { = e**( g + n loge(2) ) }
  827. px := d * LOG2E;
  828. qx := Trunc( px + 0.5 ); { Trunc() truncates toward -infinity. }
  829. n := Trunc(qx);
  830. d := d - qx * C1;
  831. d := d + qx * C2;
  832. { rational approximation for exponential }
  833. { of the fractional part: }
  834. { e**x - 1 = 2x P(x**2)/( Q(x**2) - P(x**2) ) }
  835. xx := d * d;
  836. px := d * polevl( xx, P, 2 );
  837. d := px/( polevl( xx, Q, 3 ) - px );
  838. d := ldexp( d, 1 );
  839. d := d + 1.0;
  840. d := ldexp( d, n );
  841. result := d;
  842. end;
  843. end;
  844. {$endif SUPPORT_DOUBLE}
  845. {$endif}
  846. {$ifndef FPC_SYSTEM_HAS_ROUND}
  847. function fpc_round_real(d : ValReal) : int64;compilerproc;
  848. var
  849. fr: ValReal;
  850. tr: Int64;
  851. Begin
  852. fr := abs(Frac(d));
  853. tr := Trunc(d);
  854. result:=0;
  855. case softfloat_rounding_mode of
  856. float_round_nearest_even:
  857. begin
  858. if fr > 0.5 then
  859. if d >= 0 then
  860. result:=tr+1
  861. else
  862. result:=tr-1
  863. else
  864. if fr < 0.5 then
  865. result:=tr
  866. else { fr = 0.5 }
  867. { check sign to decide ... }
  868. { as in Turbo Pascal... }
  869. begin
  870. if d >= 0.0 then
  871. result:=tr+1
  872. else
  873. result:=tr;
  874. { round to even }
  875. result:=result and not(1);
  876. end;
  877. end;
  878. float_round_down:
  879. if (d >= 0.0) or
  880. (fr = 0.0) then
  881. result:=tr
  882. else
  883. result:=tr-1;
  884. float_round_up:
  885. if (d >= 0.0) and
  886. (fr <> 0.0) then
  887. result:=tr+1
  888. else
  889. result:=tr;
  890. float_round_to_zero:
  891. result:=tr;
  892. else
  893. { needed for jvm: result must be initialized on all paths }
  894. result:=0;
  895. end;
  896. end;
  897. {$endif FPC_SYSTEM_HAS_ROUND}
  898. {$ifndef FPC_SYSTEM_HAS_LN}
  899. function fpc_ln_real(d:ValReal):ValReal;compilerproc;
  900. {*****************************************************************}
  901. { Natural Logarithm }
  902. {*****************************************************************}
  903. { }
  904. { SYNOPSIS: }
  905. { }
  906. { double x, y, log(); }
  907. { }
  908. { y = ln( x ); }
  909. { }
  910. { DESCRIPTION: }
  911. { }
  912. { Returns the base e (2.718...) logarithm of x. }
  913. { }
  914. { The argument is separated into its exponent and fractional }
  915. { parts. If the exponent is between -1 and +1, the logarithm }
  916. { of the fraction is approximated by }
  917. { }
  918. { log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). }
  919. { }
  920. { Otherwise, setting z = 2(x-1)/x+1), }
  921. { }
  922. { log(x) = z + z**3 P(z)/Q(z). }
  923. { }
  924. {*****************************************************************}
  925. const P : TabCoef = (
  926. { Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
  927. 1/sqrt(2) <= x < sqrt(2) }
  928. 4.58482948458143443514E-5,
  929. 4.98531067254050724270E-1,
  930. 6.56312093769992875930E0,
  931. 2.97877425097986925891E1,
  932. 6.06127134467767258030E1,
  933. 5.67349287391754285487E1,
  934. 1.98892446572874072159E1);
  935. Q : TabCoef = (
  936. 1.50314182634250003249E1,
  937. 8.27410449222435217021E1,
  938. 2.20664384982121929218E2,
  939. 3.07254189979530058263E2,
  940. 2.14955586696422947765E2,
  941. 5.96677339718622216300E1, 0);
  942. { Coefficients for log(x) = z + z**3 P(z)/Q(z),
  943. where z = 2(x-1)/(x+1)
  944. 1/sqrt(2) <= x < sqrt(2) }
  945. R : TabCoef = (
  946. -7.89580278884799154124E-1,
  947. 1.63866645699558079767E1,
  948. -6.41409952958715622951E1, 0, 0, 0, 0);
  949. S : TabCoef = (
  950. -3.56722798256324312549E1,
  951. 3.12093766372244180303E2,
  952. -7.69691943550460008604E2, 0, 0, 0, 0);
  953. var e : Integer;
  954. z, y : Real;
  955. Label Ldone;
  956. begin
  957. if( d <= 0.0 ) then
  958. begin
  959. float_raise(float_flag_invalid);
  960. exit;
  961. end;
  962. d := frexp( d, e );
  963. { logarithm using log(x) = z + z**3 P(z)/Q(z),
  964. where z = 2(x-1)/x+1) }
  965. if( (e > 2) or (e < -2) ) then
  966. begin
  967. if( d < SQRTH ) then
  968. begin
  969. { 2( 2x-1 )/( 2x+1 ) }
  970. Dec(e, 1);
  971. z := d - 0.5;
  972. y := 0.5 * z + 0.5;
  973. end
  974. else
  975. begin
  976. { 2 (x-1)/(x+1) }
  977. z := d - 0.5;
  978. z := z - 0.5;
  979. y := 0.5 * d + 0.5;
  980. end;
  981. d := z / y;
  982. { /* rational form */ }
  983. z := d*d;
  984. z := d + d * ( z * polevl( z, R, 2 ) / p1evl( z, S, 3 ) );
  985. goto ldone;
  986. end;
  987. { logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) }
  988. if( d < SQRTH ) then
  989. begin
  990. Dec(e, 1);
  991. d := ldexp( d, 1 ) - 1.0; { 2x - 1 }
  992. end
  993. else
  994. d := d - 1.0;
  995. { rational form }
  996. z := d*d;
  997. y := d * ( z * polevl( d, P, 6 ) / p1evl( d, Q, 6 ) );
  998. y := y - ldexp( z, -1 ); { y - 0.5 * z }
  999. z := d + y;
  1000. ldone:
  1001. { recombine with exponent term }
  1002. if( e <> 0 ) then
  1003. begin
  1004. y := e;
  1005. z := z - y * 2.121944400546905827679e-4;
  1006. z := z + y * 0.693359375;
  1007. end;
  1008. result:= z;
  1009. end;
  1010. {$endif}
  1011. {$ifndef FPC_SYSTEM_HAS_SIN}
  1012. function fpc_Sin_real(d:ValReal):ValReal;compilerproc;
  1013. {*****************************************************************}
  1014. { Circular Sine }
  1015. {*****************************************************************}
  1016. { }
  1017. { SYNOPSIS: }
  1018. { }
  1019. { double x, y, sin(); }
  1020. { }
  1021. { y = sin( x ); }
  1022. { }
  1023. { DESCRIPTION: }
  1024. { }
  1025. { Range reduction is into intervals of pi/4. The reduction }
  1026. { error is nearly eliminated by contriving an extended }
  1027. { precision modular arithmetic. }
  1028. { }
  1029. { Two polynomial approximating functions are employed. }
  1030. { Between 0 and pi/4 the sine is approximated by }
  1031. { x + x**3 P(x**2). }
  1032. { Between pi/4 and pi/2 the cosine is represented as }
  1033. { 1 - x**2 Q(x**2). }
  1034. {*****************************************************************}
  1035. var y, z, zz : Real;
  1036. j, sign : Integer;
  1037. begin
  1038. { make argument positive but save the sign }
  1039. sign := 1;
  1040. if( d < 0 ) then
  1041. begin
  1042. d := -d;
  1043. sign := -1;
  1044. end;
  1045. { above this value, approximate towards 0 }
  1046. if( d > lossth ) then
  1047. begin
  1048. result := 0.0;
  1049. exit;
  1050. end;
  1051. y := Trunc( d/PIO4 ); { integer part of x/PIO4 }
  1052. { strip high bits of integer part to prevent integer overflow }
  1053. z := ldexp( y, -4 );
  1054. z := Trunc(z); { integer part of y/8 }
  1055. z := y - ldexp( z, 4 ); { y - 16 * (y/16) }
  1056. j := Trunc(z); { convert to integer for tests on the phase angle }
  1057. { map zeros to origin }
  1058. { typecast is to avoid "can't determine which overloaded function }
  1059. { to call" }
  1060. if odd( longint(j) ) then
  1061. begin
  1062. inc(j);
  1063. y := y + 1.0;
  1064. end;
  1065. j := j and 7; { octant modulo 360 degrees }
  1066. { reflect in x axis }
  1067. if( j > 3) then
  1068. begin
  1069. sign := -sign;
  1070. dec(j, 4);
  1071. end;
  1072. { Extended precision modular arithmetic }
  1073. z := ((d - y * DP1) - y * DP2) - y * DP3;
  1074. zz := z * z;
  1075. if( (j=1) or (j=2) ) then
  1076. y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 )
  1077. else
  1078. { y = z + z * (zz * polevl( zz, sincof, 5 )); }
  1079. y := z + z * z * z * polevl( zz, sincof, 5 );
  1080. if(sign < 0) then
  1081. y := -y;
  1082. result := y;
  1083. end;
  1084. {$endif}
  1085. {$ifndef FPC_SYSTEM_HAS_COS}
  1086. function fpc_Cos_real(d:ValReal):ValReal;compilerproc;
  1087. {*****************************************************************}
  1088. { Circular cosine }
  1089. {*****************************************************************}
  1090. { }
  1091. { Circular cosine }
  1092. { }
  1093. { SYNOPSIS: }
  1094. { }
  1095. { double x, y, cos(); }
  1096. { }
  1097. { y = cos( x ); }
  1098. { }
  1099. { DESCRIPTION: }
  1100. { }
  1101. { Range reduction is into intervals of pi/4. The reduction }
  1102. { error is nearly eliminated by contriving an extended }
  1103. { precision modular arithmetic. }
  1104. { }
  1105. { Two polynomial approximating functions are employed. }
  1106. { Between 0 and pi/4 the cosine is approximated by }
  1107. { 1 - x**2 Q(x**2). }
  1108. { Between pi/4 and pi/2 the sine is represented as }
  1109. { x + x**3 P(x**2). }
  1110. {*****************************************************************}
  1111. var y, z, zz : Real;
  1112. j, sign : Integer;
  1113. i : LongInt;
  1114. begin
  1115. { make argument positive }
  1116. sign := 1;
  1117. if( d < 0 ) then
  1118. d := -d;
  1119. { above this value, round towards zero }
  1120. if( d > lossth ) then
  1121. begin
  1122. result := 0.0;
  1123. exit;
  1124. end;
  1125. y := Trunc( d/PIO4 );
  1126. z := ldexp( y, -4 );
  1127. z := Trunc(z); { integer part of y/8 }
  1128. z := y - ldexp( z, 4 ); { y - 16 * (y/16) }
  1129. { integer and fractional part modulo one octant }
  1130. i := Trunc(z);
  1131. if odd( i ) then { map zeros to origin }
  1132. begin
  1133. inc(i);
  1134. y := y + 1.0;
  1135. end;
  1136. j := i and 07;
  1137. if( j > 3) then
  1138. begin
  1139. dec(j,4);
  1140. sign := -sign;
  1141. end;
  1142. if( j > 1 ) then
  1143. sign := -sign;
  1144. { Extended precision modular arithmetic }
  1145. z := ((d - y * DP1) - y * DP2) - y * DP3;
  1146. zz := z * z;
  1147. if( (j=1) or (j=2) ) then
  1148. { y = z + z * (zz * polevl( zz, sincof, 5 )); }
  1149. y := z + z * z * z * polevl( zz, sincof, 5 )
  1150. else
  1151. y := 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 );
  1152. if(sign < 0) then
  1153. y := -y;
  1154. result := y ;
  1155. end;
  1156. {$endif}
  1157. {$ifndef FPC_SYSTEM_HAS_ARCTAN}
  1158. function fpc_ArcTan_real(d:ValReal):ValReal;compilerproc;
  1159. {*****************************************************************}
  1160. { Inverse circular tangent (arctangent) }
  1161. {*****************************************************************}
  1162. { }
  1163. { SYNOPSIS: }
  1164. { }
  1165. { double x, y, atan(); }
  1166. { }
  1167. { y = atan( x ); }
  1168. { }
  1169. { DESCRIPTION: }
  1170. { }
  1171. { Returns radian angle between -pi/2 and +pi/2 whose tangent }
  1172. { is x. }
  1173. { }
  1174. { Range reduction is from four intervals into the interval }
  1175. { from zero to tan( pi/8 ). The approximant uses a rational }
  1176. { function of degree 3/4 of the form x + x**3 P(x)/Q(x). }
  1177. {*****************************************************************}
  1178. const P : TabCoef = (
  1179. -8.40980878064499716001E-1,
  1180. -8.83860837023772394279E0,
  1181. -2.18476213081316705724E1,
  1182. -1.48307050340438946993E1, 0, 0, 0);
  1183. Q : TabCoef = (
  1184. 1.54974124675307267552E1,
  1185. 6.27906555762653017263E1,
  1186. 9.22381329856214406485E1,
  1187. 4.44921151021319438465E1, 0, 0, 0);
  1188. { tan( 3*pi/8 ) }
  1189. T3P8 = 2.41421356237309504880;
  1190. { tan( pi/8 ) }
  1191. TP8 = 0.41421356237309504880;
  1192. var y,z : Real;
  1193. Sign : Integer;
  1194. begin
  1195. { make argument positive and save the sign }
  1196. sign := 1;
  1197. if( d < 0.0 ) then
  1198. begin
  1199. sign := -1;
  1200. d := -d;
  1201. end;
  1202. { range reduction }
  1203. if( d > T3P8 ) then
  1204. begin
  1205. y := PIO2;
  1206. d := -( 1.0/d );
  1207. end
  1208. else if( d > TP8 ) then
  1209. begin
  1210. y := PIO4;
  1211. d := (d-1.0)/(d+1.0);
  1212. end
  1213. else
  1214. y := 0.0;
  1215. { rational form in x**2 }
  1216. z := d * d;
  1217. y := y + ( polevl( z, P, 3 ) / p1evl( z, Q, 4 ) ) * z * d + d;
  1218. if( sign < 0 ) then
  1219. y := -y;
  1220. result := y;
  1221. end;
  1222. {$endif}
  1223. {$ifndef FPC_SYSTEM_HAS_FRAC}
  1224. function fpc_frac_real(d : ValReal) : ValReal;compilerproc;
  1225. begin
  1226. result := d - Int(d);
  1227. end;
  1228. {$endif}
  1229. {$ifdef FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
  1230. {$ifndef FPC_SYSTEM_HAS_QWORD_TO_DOUBLE}
  1231. function fpc_qword_to_double(q : qword): double; compilerproc;
  1232. begin
  1233. result:=dword(q and $ffffffff)+dword(q shr 32)*double(4294967296.0);
  1234. end;
  1235. {$endif FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1236. {$ifndef FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1237. function fpc_int64_to_double(i : int64): double; compilerproc;
  1238. begin
  1239. if i<0 then
  1240. result:=-double(qword(-i))
  1241. else
  1242. result:=qword(i);
  1243. end;
  1244. {$endif FPC_SYSTEM_HAS_INT64_TO_DOUBLE}
  1245. {$endif FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
  1246. {$ifdef SUPPORT_DOUBLE}
  1247. {****************************************************************************
  1248. Helper routines to support old TP styled reals
  1249. ****************************************************************************}
  1250. {$ifndef FPC_SYSTEM_HAS_REAL2DOUBLE}
  1251. function real2double(r : real48) : double;
  1252. var
  1253. res : array[0..7] of byte;
  1254. exponent : word;
  1255. begin
  1256. { check for zero }
  1257. if r[0]=0 then
  1258. begin
  1259. real2double:=0.0;
  1260. exit;
  1261. end;
  1262. { copy mantissa }
  1263. res[0]:=0;
  1264. res[1]:=r[1] shl 5;
  1265. res[2]:=(r[1] shr 3) or (r[2] shl 5);
  1266. res[3]:=(r[2] shr 3) or (r[3] shl 5);
  1267. res[4]:=(r[3] shr 3) or (r[4] shl 5);
  1268. res[5]:=(r[4] shr 3) or (r[5] and $7f) shl 5;
  1269. res[6]:=(r[5] and $7f) shr 3;
  1270. { copy exponent }
  1271. { correct exponent: }
  1272. exponent:=(word(r[0])+(1023-129));
  1273. res[6]:=res[6] or ((exponent and $f) shl 4);
  1274. res[7]:=exponent shr 4;
  1275. { set sign }
  1276. res[7]:=res[7] or (r[5] and $80);
  1277. real2double:=double(res);
  1278. end;
  1279. {$endif FPC_SYSTEM_HAS_REAL2DOUBLE}
  1280. {$endif SUPPORT_DOUBLE}
  1281. {$ifdef SUPPORT_EXTENDED}
  1282. { fast 10^n routine }
  1283. function FPower10(val: Extended; Power: Longint): Extended;
  1284. const
  1285. pow32 : array[0..31] of extended =
  1286. (
  1287. 1e0,1e1,1e2,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,
  1288. 1e11,1e12,1e13,1e14,1e15,1e16,1e17,1e18,1e19,1e20,
  1289. 1e21,1e22,1e23,1e24,1e25,1e26,1e27,1e28,1e29,1e30,
  1290. 1e31
  1291. );
  1292. pow512 : array[0..15] of extended =
  1293. (
  1294. 1,1e32,1e64,1e96,1e128,1e160,1e192,1e224,
  1295. 1e256,1e288,1e320,1e352,1e384,1e416,1e448,
  1296. 1e480
  1297. );
  1298. pow4096 : array[0..9] of extended =
  1299. (1,1e512,1e1024,1e1536,
  1300. 1e2048,1e2560,1e3072,1e3584,
  1301. 1e4096,1e4608
  1302. );
  1303. negpow32 : array[0..31] of extended =
  1304. (
  1305. 1e-0,1e-1,1e-2,1e-3,1e-4,1e-5,1e-6,1e-7,1e-8,1e-9,1e-10,
  1306. 1e-11,1e-12,1e-13,1e-14,1e-15,1e-16,1e-17,1e-18,1e-19,1e-20,
  1307. 1e-21,1e-22,1e-23,1e-24,1e-25,1e-26,1e-27,1e-28,1e-29,1e-30,
  1308. 1e-31
  1309. );
  1310. negpow512 : array[0..15] of extended =
  1311. (
  1312. 0,1e-32,1e-64,1e-96,1e-128,1e-160,1e-192,1e-224,
  1313. 1e-256,1e-288,1e-320,1e-352,1e-384,1e-416,1e-448,
  1314. 1e-480
  1315. );
  1316. negpow4096 : array[0..9] of extended =
  1317. (
  1318. 0,1e-512,1e-1024,1e-1536,
  1319. 1e-2048,1e-2560,1e-3072,1e-3584,
  1320. 1e-4096,1e-4608
  1321. );
  1322. begin
  1323. if Power<0 then
  1324. begin
  1325. Power:=-Power;
  1326. result:=val*negpow32[Power and $1f];
  1327. power:=power shr 5;
  1328. if power<>0 then
  1329. begin
  1330. result:=result*negpow512[Power and $f];
  1331. power:=power shr 4;
  1332. if power<>0 then
  1333. begin
  1334. if power<=9 then
  1335. result:=result*negpow4096[Power]
  1336. else
  1337. result:=1.0/0.0;
  1338. end;
  1339. end;
  1340. end
  1341. else
  1342. begin
  1343. result:=val*pow32[Power and $1f];
  1344. power:=power shr 5;
  1345. if power<>0 then
  1346. begin
  1347. result:=result*pow512[Power and $f];
  1348. power:=power shr 4;
  1349. if power<>0 then
  1350. begin
  1351. if power<=9 then
  1352. result:=result*pow4096[Power]
  1353. else
  1354. result:=1.0/0.0;
  1355. end;
  1356. end;
  1357. end;
  1358. end;
  1359. {$endif SUPPORT_EXTENDED}