math.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. {
  2. This file is part of the Pas2JS run time library.
  3. Copyright (c) 2017 by Mattias Gaertner
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit Math;
  11. {$mode objfpc}
  12. interface
  13. uses
  14. SysUtils;
  15. const
  16. MinInteger = -$10000000000000;
  17. MaxInteger = $fffffffffffff;
  18. MinDouble = 5.0e-324;
  19. MaxDouble = 1.7e+308;
  20. const
  21. NaN: Double; external name 'NaN';
  22. Infinity: Double; external name 'Infinity';
  23. NegInfinity: Double; external name '-Infinity';
  24. type
  25. float = double;
  26. //EInvalidArgument = class(EMathError);
  27. function Min(const a, b: Integer): Integer; varargs; external name 'Math.min'; overload;
  28. function Max(const a, b: Integer): Integer; varargs; external name 'Math.max'; overload;
  29. function Min(const a, b: Double): Double; varargs; external name 'Math.min'; overload;
  30. function Max(const a, b: Double): Double; varargs; external name 'Math.max'; overload;
  31. function Min(const a, b: NativeLargeInt): Double; varargs; external name 'Math.min'; overload;
  32. function Max(const a, b: NativeLargeUInt): Double; varargs; external name 'Math.max'; overload;
  33. function InRange(const AValue, AMin, AMax: Integer): Boolean; assembler; overload;
  34. function InRange(const AValue, AMin, AMax: Double): Boolean; assembler; overload;
  35. function EnsureRange(const AValue, AMin, AMax: Integer): Integer; assembler; overload;
  36. function EnsureRange(const AValue, AMin, AMax: Double): Double; assembler; overload;
  37. type
  38. TRoundToRange = -37..37;
  39. function RoundTo(const AValue: Double; const Digits: TRoundToRange): Double;
  40. function SimpleRoundTo(const AValue: Double; const Digits: TRoundToRange = -2): Double;
  41. function randg(mean,stddev : float) : float;
  42. function RandomRange(const aFrom, aTo: Integer): Integer;
  43. function RandomRange(const aFrom, aTo: NativeLargeInt): NativeLargeInt;
  44. const
  45. NegativeValue = -1;
  46. ZeroValue = 0;
  47. PositiveValue = 1;
  48. function Sign(const AValue: Integer): Integer; external name 'Math.sign'; overload;
  49. function Sign(const AValue: Double): Double; external name 'Math.sign'; overload;
  50. function IsZero(const d: Double; Epsilon: Double): Boolean; overload;
  51. function IsZero(const d: Double): Boolean; overload;
  52. function IsNaN(const v: JSValue): boolean; external name {$IFDEF ECMAScript5}'isNaN'{$ELSE}'Number.isNan'{$ENDIF}; overload;
  53. function IsFinite(const d: JSValue): Boolean; external name 'isFinite'; overload;// false if NaN, positive or negative infinity
  54. function IsInfinite(const d: JSValue): Boolean; assembler; overload; // negative or positive infinity
  55. {$IFDEF ECMAScript6}
  56. function IsInteger(const d: JSValue): Boolean; external name 'Number.isInteger'; // any integer representable by a double
  57. function IsSafeInteger(const d: JSValue): Boolean; external name 'Number.isSafeInteger'; // an integer between MinInteger and MaxInteger, inclusive
  58. {$ENDIF}
  59. function SameValue(const A, B: Double; Epsilon: Double = 0.0): Boolean; overload;
  60. // function Abs is in System.pas
  61. function ArcCos(const A : Double): Double; external name 'Math.acos';
  62. function ArcCosH(const A: Double): Double; external name 'Math.acosh'; // not on IE
  63. function ArcSin(const A : Double): Double; external name 'Math.asin';
  64. function ArcSinH(const A : Double): Double; external name 'Math.asinh'; // not on IE
  65. function ArcTanH(const A: Double): Double; external name 'Math.atanh'; // not on IE
  66. function CosH(const A: Double): Double; external name 'Math.cosh'; // not on IE
  67. function ExpM1(const A: Double): Double; external name 'Math.expm1'; // not on IE
  68. function FRound(const A: Double): Double; overload; external name 'Math.fround'; // not on IE
  69. function FTrunc(const A: Double): double; overload; external name 'Math.trunc'; // not on IE
  70. function Hypot(const A : Double): Double; varargs; external name 'Math.hypot'; // not on IE
  71. function IMul(const A, B: Integer): Integer; external name 'Math.imul'; // not on IE
  72. function Log10(const A: Double): Double; external name 'Math.log10';
  73. function Log1p(const A: Double): Double; external name 'Math.log1p'; // not on IE
  74. function Log2(const A: Double): Double; external name 'Math.log2'; // not on IE
  75. function LogN(const A, Base: Double): Double;
  76. function Power(const Base, Exponent: Double): Double; external name 'Math.pow';
  77. // ln, round, sqrt, trunc, cos, sin, arctan, round, exp are in unit system
  78. function Ceil(const A: Double): Integer;
  79. function Floor(const A: Double): Integer;
  80. function Ceil64(const A: Double): NativeLargeInt;
  81. function Floor64(const A: Double): NativeLargeInt;
  82. function ldexp(x : double;const p : Integer) : double;
  83. procedure Frexp(X: double; out Mantissa: double; out Exponent: integer);
  84. function lnxp1(x : double) : double;
  85. function IntPower(base : float;const exponent : Integer) : double;
  86. procedure DivMod(Dividend: LongInt; Divisor: Word; out Result, Remainder: Word);
  87. procedure DivMod(Dividend: LongInt; Divisor: Word; out Result, Remainder: SmallInt);
  88. procedure DivMod(Dividend: DWord; Divisor: DWord; out Result, Remainder: DWord);
  89. procedure DivMod(Dividend: LongInt; Divisor: LongInt; out Result, Remainder: LongInt);
  90. { Angle conversion }
  91. function DegToRad(deg : double) : double;
  92. function RadToDeg(rad : double) : double;
  93. function GradToRad(grad : double) : double;
  94. function RadToGrad(rad : double) : double;
  95. function DegToGrad(deg : double) : double;
  96. function GradToDeg(grad : double) : double;
  97. { one cycle are 2*Pi rad }
  98. function CycleToRad(cycle : double) : double;
  99. function RadToCycle(rad : double) : double;
  100. Function DegNormalize(deg : double) : double;
  101. function Norm(const data : array of double) : double;
  102. // Statistical functions
  103. function Mean(const data : array of double) : double;
  104. function Sum(const data : array of double) : double;
  105. procedure SumsAndSquares(const data : Array of Double; out Sum,SumOfSquares : double);
  106. function StdDev(const data : array of Double) : float;
  107. procedure MeanAndStdDev(const data : array of Double; out Mean,StdDev : double);
  108. function Variance(const data : array of Double) : double;
  109. function TotalVariance(const data : array of Double) : double;
  110. function PopNStdDev(const data : array of Double) : double;
  111. function PopNVariance(const data : array of Double) : double;
  112. procedure MomentSkewKurtosis(const data : array of Double; out m1,m2,m3,m4,skew,kurtosis : double);
  113. // Financial functions
  114. Type
  115. TPaymentTime = (ptEndOfPeriod,ptStartOfPeriod);
  116. function FutureValue(ARate: double; NPeriods: Integer;
  117. APayment, APresentValue: double; APaymentTime: TPaymentTime): double;
  118. function InterestRate(NPeriods: Integer; APayment, APresentValue, AFutureValue: double;
  119. APaymentTime: TPaymentTime): double;
  120. function NumberOfPeriods(ARate, APayment, APresentValue, AFutureValue: double;
  121. APaymentTime: TPaymentTime): double;
  122. function Payment(ARate: double; NPeriods: Integer;
  123. APresentValue, AFutureValue: double; APaymentTime: TPaymentTime): double;
  124. function PresentValue(ARate: double; NPeriods: Integer;
  125. APayment, AFutureValue: double; APaymentTime: TPaymentTime): double;
  126. // Miscellaneous
  127. function IfThen(val:boolean;const ifTrue:integer; const ifFalse:integer= 0) :integer; overload;
  128. function IfThen(val:boolean;const ifTrue:double ; const ifFalse:double =0.0):double; overload;
  129. Type
  130. TValueRelationship = -1..1;
  131. const
  132. EqualsValue = 0;
  133. LessThanValue = Low(TValueRelationship);
  134. GreaterThanValue = High(TValueRelationship);
  135. function CompareValue ( const A, B : Integer) : TValueRelationship;
  136. function CompareValue ( const A, B : NativeLargeInt) : TValueRelationship;
  137. function CompareValue ( const A, B : NativeLargeUInt) : TValueRelationship;
  138. function CompareValue ( const A, B : Double; delta : Double = 0.0) : TValueRelationship;
  139. implementation
  140. function InRange(const AValue, AMin, AMax: Integer): Boolean; assembler;
  141. asm
  142. return (AValue >= AMin) && (AValue <= AMax);
  143. end;
  144. function InRange(const AValue, AMin, AMax: Double): Boolean; assembler;
  145. asm
  146. return (AValue >= AMin) && (AValue <= AMax);
  147. end;
  148. function EnsureRange(const AValue, AMin, AMax: Integer): Integer; assembler;
  149. asm
  150. if (AValue<AMin){ return AMin;
  151. } else if (AValue>AMax){ return AMax;
  152. } else return AValue;
  153. end;
  154. function EnsureRange(const AValue, AMin, AMax: Double): Double; assembler;
  155. asm
  156. if (AValue<AMin){ return AMin;
  157. } else if (AValue>AMax){ return AMax;
  158. } else return AValue;
  159. end;
  160. function RoundTo(const AValue: Double; const Digits: TRoundToRange): Double;
  161. var
  162. RV : Double;
  163. begin
  164. RV:=IntPower(10,Digits);
  165. Result:=Round(AValue/RV)*RV;
  166. end;
  167. function SimpleRoundTo(const AValue: Double; const Digits: TRoundToRange): Double;
  168. var
  169. RV : Double;
  170. begin
  171. RV := IntPower(10, -Digits);
  172. if AValue < 0 then
  173. Result := Int((AValue*RV) - 0.5)/RV
  174. else
  175. Result := Int((AValue*RV) + 0.5)/RV;
  176. end;
  177. function randg(mean,stddev : float) : float;
  178. Var
  179. U1,S2 : Float;
  180. begin
  181. repeat
  182. u1:= 2*random-1;
  183. S2:=Sqr(U1)+sqr(2*random-1);
  184. until s2<1;
  185. Result:=Sqrt(-2*ln(S2)/S2)*u1*stddev+Mean;
  186. end;
  187. function RandomRange(const aFrom, aTo: Integer): Integer;
  188. begin
  189. Result:=Random(Abs(aFrom-aTo))+Min(aTo,AFrom);
  190. end;
  191. function RandomRange(const aFrom, aTo: NativeLargeInt): NativeLargeInt;
  192. Var
  193. m : NativeLargeInt;
  194. begin
  195. if aFrom<aTo then
  196. M:=aFrom
  197. else
  198. M:=aTo;
  199. Result:=Random(Abs(aFrom-aTo))+M;
  200. end;
  201. const
  202. DZeroResolution = 1E-12;
  203. function IsZero(const d: Double; Epsilon: Double): Boolean;
  204. begin
  205. if Epsilon=0 then
  206. Epsilon:=DZeroResolution;
  207. Result:=Abs(d)<=Epsilon;
  208. end;
  209. function IsZero(const d: Double): Boolean;
  210. begin
  211. Result:=Abs(d)<=DZeroResolution;
  212. end;
  213. function IsInfinite(const d: JSValue): Boolean; assembler;
  214. asm
  215. return (d==Infinite) || (d==-Infinite);
  216. end;
  217. function SameValue(const A, B: Double; Epsilon: Double): Boolean;
  218. begin
  219. if (Epsilon=0.0) then
  220. Epsilon:=Max(Min(Abs(A),Abs(B))*DZeroResolution,DZeroResolution);
  221. if (A>B) then
  222. Result:=((A-B)<=Epsilon)
  223. else
  224. Result:=((B-A)<=Epsilon);
  225. end;
  226. function JSFloor(const A: Double): Double; external name 'Math.floor';
  227. function JSCeil(const A: Double): Double; external name 'Math.ceil';
  228. function Ceil(const A: Double): Integer;
  229. begin
  230. // TODO: add Range check ?
  231. Result:=trunc(JSCeil(a));
  232. end;
  233. function Floor(const A: Double): Integer;
  234. begin
  235. // TODO: add Range check ?
  236. Result:=trunc(JSFloor(a));
  237. end;
  238. function Ceil64(const A: Double): NativeLargeInt;
  239. begin
  240. Result:=trunc(JSCeil(a));
  241. end;
  242. function Floor64(const A: Double): NativeLargeInt;
  243. begin
  244. Result:=trunc(JSCeil(a));
  245. end;
  246. procedure Frexp(X: double; out Mantissa: double; out Exponent: integer);
  247. begin
  248. Exponent:=0;
  249. if (X<>0) then
  250. if (abs(X)<0.5) then
  251. repeat
  252. X:=X*2;
  253. Dec(Exponent);
  254. until (abs(X)>=0.5)
  255. else
  256. while (abs(X)>=1) do
  257. begin
  258. X:=X/2;
  259. Inc(Exponent);
  260. end;
  261. Mantissa:=X;
  262. end;
  263. function LogN(const A, Base: Double): Double;
  264. begin
  265. Result:=Ln(A)/Ln(Base);
  266. end;
  267. function lnxp1(x: double): double;
  268. var
  269. y: float;
  270. begin
  271. if (x>=4.0) then
  272. result:=ln(1.0+x)
  273. else
  274. begin
  275. y:=1.0+x;
  276. if (y=1.0) then
  277. result:=x
  278. else
  279. begin
  280. result:=ln(y); { lnxp1(-1) = ln(0) = -Inf }
  281. if y>0.0 then
  282. result:=result+(x-(y-1.0))/y;
  283. end;
  284. end;
  285. end;
  286. function ldexp(x : double;const p : Integer) : double;
  287. begin
  288. result:=x*intpower(2.0,p);
  289. end;
  290. function IntPower(base: float; const exponent: Integer): double;
  291. var
  292. i : longint;
  293. begin
  294. if (base = 0.0) and (exponent = 0) then
  295. result:=1
  296. else
  297. begin
  298. i:=abs(exponent);
  299. Result:=1.0;
  300. while i>0 do
  301. begin
  302. while (i and 1)=0 do
  303. begin
  304. i:=i shr 1;
  305. base:=sqr(base);
  306. end;
  307. i:=i-1;
  308. Result:=Result*base;
  309. end;
  310. if exponent<0 then
  311. Result:=1.0/Result;
  312. end;
  313. end;
  314. procedure DivMod(Dividend: LongInt; Divisor: Word; out Result, Remainder: Word);
  315. begin
  316. if Dividend < 0 then
  317. begin
  318. Dividend:=-Dividend;
  319. Result:=-(Dividend Div Divisor);
  320. Remainder:=-(Dividend+(Result*Divisor));
  321. end
  322. else
  323. begin
  324. Result:=Dividend Div Divisor;
  325. Remainder:=Dividend-(Result*Divisor);
  326. end;
  327. end;
  328. procedure DivMod(Dividend: LongInt; Divisor: Word; out Result,
  329. Remainder: SmallInt);
  330. begin
  331. if Dividend < 0 then
  332. begin
  333. Dividend:=-Dividend;
  334. Result:=-(Dividend Div Divisor);
  335. Remainder:=-(Dividend+(Result*Divisor));
  336. end
  337. else
  338. begin
  339. Result:=Dividend Div Divisor;
  340. Remainder:=Dividend-(Result*Divisor);
  341. end;
  342. end;
  343. procedure DivMod(Dividend: DWord; Divisor: DWord; out Result, Remainder: DWord);
  344. begin
  345. Result:=Dividend Div Divisor;
  346. Remainder:=Dividend-(Result*Divisor);
  347. end;
  348. procedure DivMod(Dividend: LongInt; Divisor: LongInt; out Result,
  349. Remainder: LongInt);
  350. begin
  351. if Dividend < 0 then
  352. begin
  353. Dividend:=-Dividend;
  354. Result:=-(Dividend Div Divisor);
  355. Remainder:=-(Dividend+(Result*Divisor));
  356. end
  357. else
  358. begin
  359. Result:=Dividend Div Divisor;
  360. Remainder:=Dividend-(Result*Divisor);
  361. end;
  362. end;
  363. { ---------------------------------------------------------------------
  364. Angle conversion
  365. ---------------------------------------------------------------------}
  366. function DegToRad(deg: double): double;
  367. begin
  368. Result:=deg*(pi/180.0);
  369. end;
  370. function RadToDeg(rad: double): double;
  371. begin
  372. Result:=rad*(180.0/pi);
  373. end;
  374. function GradToRad(grad: double): double;
  375. begin
  376. Result:=grad*(pi/200.0);
  377. end;
  378. function RadToGrad(rad: double): double;
  379. begin
  380. Result:=rad*(200.0/pi);
  381. end;
  382. function DegToGrad(deg: double): double;
  383. begin
  384. Result:=deg*(200.0/180.0);
  385. end;
  386. function GradToDeg(grad: double): double;
  387. begin
  388. Result:=grad*(180.0/200.0);
  389. end;
  390. function CycleToRad(cycle: double): double;
  391. begin
  392. Result:=(2*pi)*cycle;
  393. end;
  394. function RadToCycle(rad: double): double;
  395. begin
  396. Result:=rad*(1/(2*pi));
  397. end;
  398. function DegNormalize(deg: double): double;
  399. begin
  400. Result:=Deg-Int(Deg/360)*360;
  401. If (Result<0) then Result:=Result+360;
  402. end;
  403. function sumofsquares(const data : array of double) : double;
  404. var
  405. i,N : longint;
  406. begin
  407. N:=Length(Data);
  408. Result:=0.0;
  409. for i:=0 to N-1 do
  410. Result:=Result+sqr(data[i]);
  411. end;
  412. function Norm(const data: array of double): double;
  413. begin
  414. Result:=sqrt(sumofsquares(data));
  415. end;
  416. { ---------------------------------------------------------------------
  417. Statistical functions
  418. ---------------------------------------------------------------------}
  419. function Sum(const data: array of double): double;
  420. var
  421. i,N : longint;
  422. begin
  423. N:=Length(Data);
  424. Result:=0.0;
  425. for i:=0 to N-1 do
  426. Result:=Result+data[i];
  427. end;
  428. function Mean(const data: array of double): double;
  429. Var
  430. N : integer;
  431. begin
  432. N:=Length(Data);
  433. if N=0 then
  434. Result:=0
  435. else
  436. Result:=Sum(Data)/N;
  437. end;
  438. procedure SumsAndSquares(const data: array of Double; out Sum,
  439. SumOfSquares: double);
  440. var
  441. i,n : Integer;
  442. t,s,ss: double;
  443. begin
  444. n:=length(Data);
  445. ss:=0.0; // Use local vars, var is very inefficient in js
  446. s:=0.0;
  447. for i:=0 to N-1 do
  448. begin
  449. t:=data[i];
  450. ss:=ss+sqr(t);
  451. s:=s+t;
  452. end;
  453. Sum:=s;
  454. SumOfSquares:=ss;
  455. end;
  456. function StdDev(const data: array of Double): float;
  457. begin
  458. Result:=Sqrt(Variance(Data));
  459. end;
  460. function Variance(const data: array of Double): double;
  461. var
  462. n : integer;
  463. begin
  464. N:=Length(Data);
  465. If N=1 then
  466. Result:=0
  467. else
  468. Result:=TotalVariance(Data)/(N-1);
  469. end;
  470. function TotalVariance(const data: array of Double): double;
  471. var
  472. S,SS : Float;
  473. N : integer;
  474. begin
  475. N:=Length(Data);
  476. If Length(Data)=1 then
  477. Result:=0
  478. else
  479. begin
  480. SumsAndSquares(Data,S,SS);
  481. Result := SS-Sqr(S)/N;
  482. end;
  483. end;
  484. procedure MeanAndStdDev(const data: array of Double; out Mean, StdDev: double);
  485. Var
  486. I,N : longint;
  487. M,S : Double;
  488. begin
  489. N:=Length(Data);
  490. M:=0;
  491. S:=0;
  492. For I:=0 to N-1 do
  493. begin
  494. M:=M+Data[i];
  495. S:=S+Sqr(Data[i]);
  496. end;
  497. M:=M/N;
  498. S:=(S-N*Sqr(M));
  499. If N>1 then
  500. S:=Sqrt(S/(N-1))
  501. else
  502. S:=0;
  503. Mean:=M;
  504. StdDev:=S;
  505. end;
  506. function PopNStdDev(const data : array of Double) : double;
  507. begin
  508. Result:=Sqrt(PopnVariance(Data));
  509. end;
  510. function PopNVariance(const data : array of Double) : double;
  511. Var
  512. N : integer;
  513. begin
  514. N:=Length(Data);
  515. if N=0 then
  516. Result:=0
  517. else
  518. Result:=TotalVariance(Data)/N;
  519. end;
  520. procedure MomentSkewKurtosis(const data: array of Double; out m1, m2, m3, m4, skew, kurtosis: double);
  521. var
  522. i,N: integer;
  523. deviation, deviation2: double;
  524. reciprocalN: float;
  525. // Use local vars for all calculations, var is very slow
  526. lm1, lm2, lm3, lm4, lskew, lkurtosis: double;
  527. begin
  528. N:=length(Data);
  529. lm1 := 0;
  530. reciprocalN := 1/N;
  531. for i := 0 to N-1 do
  532. lm1 := lm1 + data[i];
  533. lm1 := reciprocalN * lm1;
  534. lm2 := 0;
  535. lm3 := 0;
  536. lm4 := 0;
  537. for i := 0 to N-1 do
  538. begin
  539. deviation := (data[i]-lm1);
  540. deviation2 := deviation * deviation;
  541. lm2 := lm2 + deviation2;
  542. lm3 := lm3 + deviation2 * deviation;
  543. lm4 := lm4 + deviation2 * deviation2;
  544. end;
  545. lm2 := reciprocalN * lm2;
  546. lm3 := reciprocalN * lm3;
  547. lm4 := reciprocalN * lm4;
  548. lskew := lm3 / (sqrt(lm2)*lm2);
  549. lkurtosis := lm4 / (lm2 * lm2);
  550. m1:=lm1;
  551. m2:=lm2;
  552. m3:=lm3;
  553. m4:=lm4;
  554. skew:=lskew;
  555. kurtosis:=lkurtosis;
  556. end;
  557. { ---------------------------------------------------------------------
  558. Financial functions
  559. ---------------------------------------------------------------------}
  560. function FutureValue(ARate: double; NPeriods: Integer;
  561. APayment, APresentValue: double; APaymentTime: TPaymentTime): double;
  562. var
  563. q, qn, factor: double;
  564. begin
  565. if ARate = 0 then
  566. Result := -APresentValue - APayment * NPeriods
  567. else begin
  568. q := 1.0 + ARate;
  569. qn := power(q, NPeriods);
  570. factor := (qn - 1) / (q - 1);
  571. if APaymentTime = ptStartOfPeriod then
  572. factor := factor * q;
  573. Result := -(APresentValue * qn + APayment*factor);
  574. end;
  575. end;
  576. function InterestRate(NPeriods: Integer; APayment, APresentValue, AFutureValue: double;
  577. APaymentTime: TPaymentTime): double;
  578. { The interest rate cannot be calculated analytically. We solve the equation
  579. numerically by means of the Newton method:
  580. - guess value for the interest reate
  581. - calculate at which interest rate the tangent of the curve fv(rate)
  582. (straight line!) has the requested future vale.
  583. - use this rate for the next iteration. }
  584. const
  585. DELTA = 0.001;
  586. EPS = 1E-9; // required precision of interest rate (after typ. 6 iterations)
  587. MAXIT = 20; // max iteration count to protect agains non-convergence
  588. var
  589. r1, r2, dr: double;
  590. fv1, fv2: double;
  591. iteration: Integer;
  592. begin
  593. iteration := 0;
  594. r1 := 0.05; // inital guess
  595. repeat
  596. r2 := r1 + DELTA;
  597. fv1 := FutureValue(r1, NPeriods, APayment, APresentValue, APaymentTime);
  598. fv2 := FutureValue(r2, NPeriods, APayment, APresentValue, APaymentTime);
  599. dr := (AFutureValue - fv1) / (fv2 - fv1) * delta; // tangent at fv(r)
  600. r1 := r1 + dr; // next guess
  601. inc(iteration);
  602. until (abs(dr) < EPS) or (iteration >= MAXIT);
  603. Result := r1;
  604. end;
  605. function NumberOfPeriods(ARate, APayment, APresentValue, AFutureValue: double;
  606. APaymentTime: TPaymentTime): double;
  607. { Solve the cash flow equation (1) for q^n and take the logarithm }
  608. var
  609. q, x1, x2: double;
  610. begin
  611. if ARate = 0 then
  612. Result := -(APresentValue + AFutureValue) / APayment
  613. else begin
  614. q := 1.0 + ARate;
  615. if APaymentTime = ptStartOfPeriod then
  616. APayment := APayment * q;
  617. x1 := APayment - AFutureValue * ARate;
  618. x2 := APayment + APresentValue * ARate;
  619. if (x2 = 0) // we have to divide by x2
  620. or (sign(x1) * sign(x2) < 0) // the argument of the log is negative
  621. then
  622. Result := Infinity
  623. else begin
  624. Result := ln(x1/x2) / ln(q);
  625. end;
  626. end;
  627. end;
  628. function Payment(ARate: double; NPeriods: Integer;
  629. APresentValue, AFutureValue: double; APaymentTime: TPaymentTime): double;
  630. var
  631. q, qn, factor: double;
  632. begin
  633. if ARate = 0 then
  634. Result := -(AFutureValue + APresentValue) / NPeriods
  635. else begin
  636. q := 1.0 + ARate;
  637. qn := power(q, NPeriods);
  638. factor := (qn - 1) / (q - 1);
  639. if APaymentTime = ptStartOfPeriod then
  640. factor := factor * q;
  641. Result := -(AFutureValue + APresentValue * qn) / factor;
  642. end;
  643. end;
  644. function PresentValue(ARate: double; NPeriods: Integer;
  645. APayment, AFutureValue: double; APaymentTime: TPaymentTime): double;
  646. var
  647. q, qn, factor: double;
  648. begin
  649. if ARate = 0.0 then
  650. Result := -AFutureValue - APayment * NPeriods
  651. else begin
  652. q := 1.0 + ARate;
  653. qn := power(q, NPeriods);
  654. factor := (qn - 1) / (q - 1);
  655. if APaymentTime = ptStartOfPeriod then
  656. factor := factor * q;
  657. Result := -(AFutureValue + APayment*factor) / qn;
  658. end;
  659. end;
  660. { ---------------------------------------------------------------------
  661. Miscellaneous
  662. ---------------------------------------------------------------------}
  663. function IfThen(val: boolean; const ifTrue: integer; const ifFalse: integer): integer;
  664. begin
  665. if val then result:=iftrue else result:=iffalse;
  666. end;
  667. function IfThen(val: boolean; const ifTrue: double; const ifFalse: double): double;
  668. begin
  669. if val then result:=iftrue else result:=iffalse;
  670. end;
  671. function CompareValue(const A, B : Integer): TValueRelationship;
  672. begin
  673. result:=GreaterThanValue;
  674. if a=b then
  675. result:=EqualsValue
  676. else
  677. if a<b then
  678. result:=LessThanValue;
  679. end;
  680. function CompareValue(const A, B: NativeLargeInt): TValueRelationship;
  681. begin
  682. result:=GreaterThanValue;
  683. if a=b then
  684. result:=EqualsValue
  685. else
  686. if a<b then
  687. result:=LessThanValue;
  688. end;
  689. function CompareValue(const A, B: NativeLargeUInt): TValueRelationship;
  690. begin
  691. result:=GreaterThanValue;
  692. if a=b then
  693. result:=EqualsValue
  694. else
  695. if a<b then
  696. result:=LessThanValue;
  697. end;
  698. function CompareValue(const A, B: Double; delta: Double): TValueRelationship;
  699. begin
  700. result:=GreaterThanValue;
  701. if abs(a-b)<=delta then
  702. result:=EqualsValue
  703. else
  704. if a<b then
  705. result:=LessThanValue;
  706. end;
  707. end.