home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / unity / d45 / ESBMATHS.ZIP / ESBMaths.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-19  |  73KB  |  2,759 lines

  1. unit ESBMaths;
  2.  
  3. {:
  4.     ESBMaths 3.2.1 - contains useful Mathematical routines for Delphi 4, 5 & 6.
  5.  
  6.     Copyright ⌐1997-2001 ESB Consultancy<p>
  7.  
  8.     These routines are used by ESB Consultancy within the
  9.     development of their Customised Applications, and have been
  10.     under Development since the early Turbo Pascal days. Many of the routines were developed
  11.     for specific needs.<p>
  12.  
  13.     ESB Consultancy retains full copyright.<p>
  14.  
  15.     ESB Consultancy grants users of this code royalty free rights
  16.     to do with this code as they wish.<p>
  17.  
  18.     ESB Consultancy makes no guarantees nor excepts any liabilities
  19.     due to the use of these routines<p>
  20.  
  21.     We does ask that if this code helps you in you development
  22.     that you send as an email mailto:glenn@esbconsult.com.au or even
  23.     a local postcard. It would also be nice if you gave us a
  24.     mention in your About Box or Help File.<p>
  25.  
  26.     ESB Consultancy Home Page: http://www.esbconsult.com.au<p>
  27.  
  28.     Mail Address: PO Box 2259, Boulder, WA 6449 AUSTRALIA<p>
  29.  
  30.     Check out our new ESB Professional Computation Suite with
  31.     3000+ Routines and 80+ Components for Delphi 4, 5 & 6.<p>
  32.     http://www.esbconsult.com.au/esbpcs.html<p>
  33.  
  34.     Also check out Marcel Martin's HIT at:<p>
  35.     http://www.esbconsult.com.au/esbpcs-hit.html<p>
  36.     Marcel has been helping out to optimise and improve routines.<p>
  37.  
  38.     Rory Daulton has generously donated and helped with many optimised
  39.     routines. Our thanks to him as well.<p>
  40.  
  41.     Marcel van Brakel has also been very helpful has includes ESBMaths
  42.     into the Jedi Collection. http://www.delphi-jedi.org/<p>
  43.  
  44.     Any mistakes made are mine rather than Rory's or the Marcels'.<p>
  45.  
  46.     History: See Whatsnew.txt
  47. }
  48.  
  49. interface
  50. {$IFDEF VER120}
  51. {$DEFINE D4andAbove}
  52. {$ENDIF}
  53.  
  54. {$IFDEF VER125}
  55. {$DEFINE D4andAbove}
  56. {$ENDIF}
  57.  
  58. {$IFDEF VER130}
  59. {$DEFINE D4andAbove}
  60. {$ENDIF}
  61.  
  62. {$IFDEF VER140}
  63. {$DEFINE D4andAbove}
  64. {$ENDIF}
  65.  
  66. {$J-} // Constants from here are not assignable
  67. const
  68.     //: Smallest Magnitude Single Available.
  69.     MinSingle: Single = 1.5e-45;
  70.     //: Largest Magnitude Single Available.
  71.     MaxSingle: Single = 3.4e+38;
  72.     //: Smallest Magnitude Double Available.
  73.     MinDouble: Double = 5.0e-324;
  74.     //: Largest Magnitude Double Available.
  75.     MaxDouble: Double = 1.7e+308;
  76.     //: Smallest Magnitude Extended Available.
  77.     MinExtended: Extended = 3.6e-4951;
  78.     //: Largest Magnitude Extended Available.
  79.     MaxExtended: Extended = 1.1e+4932;
  80.     // Smallest Delphi Currency Value.
  81.     MinCurrency: Currency = -922337203685477.5807;
  82.     // Largest Delphi Currency Value.
  83.     MaxCurrency: Currency = 922337203685477.5807;
  84.  
  85. {--- Mathematical Constants ---}
  86.  
  87. {--- Taken from Abramowitz & Stegun: "Handbook of Mathematical Functions"
  88.     and other sources ----}
  89.  
  90. const
  91.     //: Square Root of 2.
  92.     Sqrt2: Extended    = 1.4142135623730950488;
  93.  
  94.     //: Square Root of 3.
  95.     Sqrt3: Extended    = 1.7320508075688772935;
  96.  
  97.     //: Square Root of 5.
  98.     Sqrt5: Extended    = 2.2360679774997896964;
  99.  
  100.     //: Square Root of 10.
  101.     Sqrt10: Extended = 3.1622776601683793320;
  102.  
  103.     //: Square Root of Pi.
  104.     SqrtPi: Extended = 1.77245385090551602729;
  105.  
  106.     //: Cube Root of 2.
  107.     Cbrt2: Extended  = 1.2599210498948731648;
  108.  
  109.     //: Cube Root of 3.
  110.     Cbrt3: Extended  = 1.4422495703074083823;
  111.  
  112.     //: Cube Root of 10.
  113.     Cbrt10: Extended = 2.1544346900318837219;
  114.  
  115.     //: Cube Root of 100.
  116.     Cbrt100: Extended = 4.6415888336127788924;
  117.  
  118.     //: Cube Root of Pi.
  119.     CbrtPi: Extended = 1.4645918875615232630;
  120.  
  121.     //: Inverse of Square Root of 2.
  122.     InvSqrt2: Extended = 0.70710678118654752440;
  123.  
  124.     //: Inverse of Square Root of 3.
  125.     InvSqrt3: Extended = 0.57735026918962576451;
  126.  
  127.     //: Inverse of Square Root of 5.
  128.     InvSqrt5: Extended = 0.44721359549995793928;
  129.  
  130.     //: Inverse of Square Root of Pi.
  131.     InvSqrtPi: Extended = 0.56418958354775628695;
  132.  
  133.     //: Inverse of Cube Root of Pi.
  134.     InvCbrtPi: Extended    = 0.68278406325529568147;
  135.  
  136.     //: Natural Constant.
  137.     ESBe: Extended     = 2.7182818284590452354;
  138.  
  139.     //: Square of Natural Constant.
  140.     ESBe2: Extended = 7.3890560989306502272;
  141.  
  142.     //: Natural Constant raised to Pi.
  143.     ESBePi: Extended = 23.140692632779269006;
  144.  
  145.     //: Natural Constant raised to Pi/2.
  146.     ESBePiOn2: Extended = 4.8104773809653516555;
  147.  
  148.     //: Natural Constant raised to Pi/4.
  149.     ESBePiOn4: Extended = 2.1932800507380154566;
  150.  
  151.     //: Natural Log of 2.
  152.     Ln2: Extended    = 0.69314718055994530942;
  153.  
  154.     //: Natural Log of 10.
  155.     Ln10: Extended = 2.30258509299404568402;
  156.  
  157.     //: Natural Log of Pi.
  158.     LnPi: Extended = 1.14472988584940017414;
  159.  
  160.     //: Log to Base 2 of 10.
  161.     Log10Base2 = 3.3219280948873623478;
  162.  
  163.     //: Log to Base 10 of 2.
  164.     Log2Base10: Extended = 0.30102999566398119521;
  165.  
  166.     //: Log to Base 10 of 3.
  167.     Log3Base10: Extended = 0.47712125471966243730;
  168.  
  169.     //: Log to Base 10 of Pi.
  170.     LogPiBase10: Extended    = 0.4971498726941339;
  171.  
  172.     //: Log to Base 10 of Natural Constant.
  173.     LogEBase10: Extended = 0.43429448190325182765;
  174.  
  175.     //: Accurate Pi Constant.
  176.     ESBPi: Extended = 3.1415926535897932385;
  177.  
  178.     //: Inverse of Pi.
  179.     InvPi: Extended = 3.1830988618379067154e-1;
  180.  
  181.     //: Two * Pi.
  182.     TwoPi: Extended = 6.2831853071795864769;
  183.  
  184.     //: Three * Pi.
  185.     ThreePi: Extended = 9.4247779607693797153;
  186.  
  187.     //: Square of Pi.
  188.     Pi2: Extended    = 9.8696044010893586188;
  189.  
  190.     //: Pi raised to the Natural Constant.
  191.     PiToE: Extended    = 22.459157718361045473;
  192.  
  193.     //: Half of Pi.
  194.     PiOn2: Extended = 1.5707963267948966192;
  195.  
  196.     //: Third of Pi.
  197.     PiOn3: Extended = 1.0471975511965977462;
  198.  
  199.     //: Quarter of Pi.
  200.     PiOn4: Extended = 0.7853981633974483096;
  201.  
  202.     //: Three Halves of Pi.
  203.     ThreePiOn2: Extended = 4.7123889803846898577;
  204.  
  205.     //: Four Thirds of Pi.
  206.     FourPiOn3: Extended =  4.1887902047863909846;
  207.  
  208.     //: 2^63.
  209.     TwoToPower63: Extended = 9223372036854775808.0;
  210.  
  211.     //: One Radian in Degrees.
  212.     OneRadian: Extended    = 57.295779513082320877;
  213.  
  214.     //: One Degree in Radians.
  215.     OneDegree: Extended    = 1.7453292519943295769E-2;
  216.  
  217.     //: One Minute in Radians.
  218.     OneMinute: Extended    = 2.9088820866572159615E-4;
  219.  
  220.     //: One Second in Radians.
  221.     OneSecond: Extended    = 4.8481368110953599359E-6;
  222.  
  223.     //: Gamma Constant.
  224.     ESBGamma: Extended    = 0.57721566490153286061;
  225.  
  226.     //: Natural Log of the Square Root of (2 * Pi)
  227.     LnRt2Pi: Extended = 9.189385332046727E-1;
  228.  
  229. {$IFNDEF D4andAbove}
  230. type
  231.     LongWord = Cardinal;
  232. {$ENDIF}
  233.  
  234. type
  235.     {: Used for a Bit List of 16 bits from 15 -> 0 }
  236.     TBitList = Word;
  237.  
  238. var
  239.     {: Tolerance used to decide when float close enough to zero.
  240.         For MAXIMUM Tolerance use  MinExtended (3.6e-4951). }
  241.     ESBTolerance: Extended = 5.0e-324; // MinDouble
  242.  
  243. {--- Integer Operations ---}
  244.  
  245. {$IFDEF D4andAbove}
  246. {: Multiply two unsigned 32-bit integers, checking for overflow.
  247.     EXCEPTIONS: EIntOverflow  if the product will not fit into a LongWord.<p>
  248.     NOTES: 1. This is needed in Delphi 5.01, since an attempt to multiply two
  249.         LongWords results in signed multiplication.<p>
  250.     Developed By Rory Daulton - used with permission.
  251. }
  252. function UMul (const Num1, Num2: LongWord): LongWord;
  253.  
  254. {: Multiply two unsigned 32-bit integers then divide by 2**32 (ie
  255.     return the upper DWORD of the product).
  256.     EXCEPTIONS: None, since the answer always fits into 32 bits.<p>
  257.     NOTES: This is useful in randomizing routines, to scale one integer by
  258.         the other relative to 32 bits (reduce one integer according to the
  259.         size of a second integer).<p>
  260.     Developed By Rory Daulton - used with permission.
  261. }
  262. function UMulDiv2p32 (const Num1, Num2: LongWord): LongWord;
  263.  
  264.  
  265. {: Multiply two unsigned 32-bit integers then divide by another unsigned 32-bit integer.
  266.     EXCEPTIONS: EDivByZero  if the divisor is zero (see Note 1). <p>
  267.     NOTES: 1. The product followed by division will cause an unflagged integer
  268.         overflow if the answer will not fit into 32 bits. In this case, the
  269.         returned value is the lower 32-bits of the true answer.  This will
  270.         never be a problem if the two multipliers are below the divisor.<p>
  271.         2. The result is truncated toward zero (as in most integer divides).<p>
  272.         3. This is useful in randomizing routines, to scale one integer by
  273.         the other relative to a third (reduce one integer according to
  274.         the relative size of a second integer compared to a third integer).<p>
  275.         4. The Win32 API has a similar function MulDiv(), but it works on
  276.         signed integers and rounds the quotient.<p>
  277.     Developed By Rory Daulton - used with permission.
  278. }
  279. function UMulDiv (const Num1, Num2, Divisor: LongWord): LongWord;
  280.  
  281. {: Multiply two unsigned 32-bit integers then take the modulus by another
  282.     unsigned 32-bit integer.
  283.     EXCEPTIONS: EDivByZero   if the divisor is zero (See Note 1).<p>
  284.     NOTES: 1. There is never an overflow error, since the answer always fits
  285.         into 32 bits.<p>
  286.         2. This is useful in linear congruential generators.<p>
  287.     Developed By Rory Daulton - used with permission.
  288. }
  289. function UMulMod (const Num1, Num2, Modulus: LongWord): LongWord;
  290.  
  291. {$ENDIF}
  292.  
  293. {: Returns True if X1 and X2 are within ESBTolerance of each other }
  294. function SameFloat (const X1, X2: Extended): Boolean;
  295.  
  296. {: Returns True if X is within ESBTolerance of 0 }
  297. function FloatIsZero (const X: Extended): Boolean;
  298.  
  299. {: Returns True if X is Positive, ie X > ESBTolerance.
  300. }
  301. function FloatIsPositive (const X: Extended): Boolean;
  302.  
  303. {: Returns True if X is Negative, ie X < -ESBTolerance.
  304. }
  305. function FloatIsNegative (const X: Extended): Boolean;
  306.  
  307. {: Increments a Byte up to Limit. If B >= Limit no increment occurs. }
  308. procedure IncLim (var B: Byte; const Limit: Byte);
  309.  
  310. {: Increments a ShortInt up to Limit. If B >= Limit no increment occurs. }
  311. procedure IncLimSI (var B: ShortInt; const Limit: ShortInt);
  312.  
  313. {: Increments a Word up to Limit. If B >= Limit no increment occurs. }
  314. procedure IncLimW (var B: Word; const Limit: Word);
  315.  
  316. {: Increments an Integer up to Limit. If B >= Limit no increment occurs. }
  317. procedure IncLimI (var B: Integer; const Limit: Integer);
  318.  
  319. {: Increments a LongInt up to Limit. If B >= Limit no increment occurs. }
  320. procedure IncLimL (var B: LongInt; const Limit: LongInt);
  321.  
  322. {: Decrements a Byte down to Limit. If B <= Limit no increment occurs. BASM }
  323. procedure DecLim (var B: Byte; const Limit: Byte);
  324.  
  325. {: Decrements a ShortInt down to Limit. If B <= Limit no increment occurs. }
  326. procedure DecLimSI (var B: ShortInt; const Limit: ShortInt);
  327.  
  328. {: Decrements a Word down to Limit. If B <= Limit no increment occurs. }
  329. procedure DecLimW (var B: Word; const Limit: Word);
  330.  
  331. {: Decrements an Integer down to Limit. If B <= Limit no increment occurs. }
  332. procedure DecLimI (var B: Integer; const Limit: Integer);
  333.  
  334. {: Decrements a LongInt down to Limit. If B <= Limit no increment occurs. }
  335. procedure DecLimL (var B: LongInt; const Limit: LongInt);
  336.  
  337. {: Returns the maximum value between two Bytes. BASM }
  338. function MaxB (const B1, B2: Byte): Byte;
  339.  
  340. {: Returns the minimum value between two Bytes. BASM }
  341. function MinB (const B1, B2: Byte): Byte;
  342.  
  343. {: Returns the maximum value between two ShortInts. }
  344. function MaxSI (const B1, B2: ShortInt): ShortInt;
  345.  
  346. {: Returns the minimum value between two ShortInts. }
  347. function MinSI (const B1, B2: ShortInt): ShortInt;
  348.  
  349. {: Returns the maximum value between two Words. BASM }
  350. function MaxW (const B1, B2: Word): Word;
  351.  
  352. {: Returns the minimum value between two Words. BASM }
  353. function MinW (const B1, B2: Word): Word;
  354.  
  355. {: Returns the maximum value between two Integers. }
  356. function MaxI (const B1, B2: Integer): Integer;
  357.  
  358. {: Returns the minimum value between two Integers. }
  359. function MinI (const B1, B2: Integer): Integer;
  360.  
  361. {: Returns the maximum value between two LongInts. }
  362. function MaxL (const B1, B2: LongInt): LongInt;
  363.  
  364. {: Returns the minimum value between two LongInts. }
  365. function MinL (const B1, B2: LongInt): LongInt;
  366.  
  367. {: Swap Two Bytes. }
  368. procedure SwapB (var B1, B2: Byte);
  369.  
  370. {: Swap Two ShortInts. }
  371. procedure SwapSI (var B1, B2: ShortInt); 
  372.  
  373. {: Swap Two Words. }
  374. procedure SwapW (var B1, B2: Word);
  375.  
  376. {: Swap Two Integers. }
  377. procedure SwapI (var B1, B2: SmallInt);
  378.  
  379. {: Swap Two LongInts. }
  380. procedure SwapL (var B1, B2: LongInt);
  381.  
  382. {: Swap Two Integers (32-bit). }
  383. procedure SwapI32 (var B1, B2: Integer);
  384.  
  385. {: Swap Two LongWords. }
  386. procedure SwapC (var B1, B2: LongWord);
  387.  
  388. {$IFDEF D4andAbove}
  389. {: Swap Two Int64's }
  390. procedure SwapInt64 (var X, Y: Int64);
  391. {$ENDIF}
  392.  
  393. {: Returns: <p>
  394.     -1  if B < 0 <p>
  395.      0  if B = 0 <p>
  396.      1  if B > 0  BASM }
  397. function Sign (const B: LongInt): ShortInt;
  398.  
  399. {: Returns the Maximum of 4 Words - BASM }
  400. function Max4Word (const X1, X2, X3, X4: Word): Word;
  401.  
  402. {: Returns the Minimum of 4 Words - BASM }
  403. function Min4Word (const X1, X2, X3, X4: Word): Word;
  404.  
  405. {: Returns the Maximum of 3 Words - BASM }
  406. function Max3Word (const X1, X2, X3: Word): Word;
  407.  
  408. {: Returns the Minimum of 3 Words - BASM }
  409. function Min3Word (const X1, X2, X3: Word): Word;
  410.  
  411. {: Returns the Maximum of an array of Bytes }
  412. function MaxBArray (const B: array of Byte): Byte;
  413.  
  414. {: Returns the Maximum of an array of Words }
  415. function MaxWArray (const B: array of Word): Word;
  416.  
  417. {: Returns the Maximum of an array of ShortInts }
  418. function MaxSIArray (const B: array of ShortInt): ShortInt;
  419.  
  420. {: Returns the Maximum of an array of Integers }
  421. function MaxIArray (const B: array of Integer): Integer;
  422.  
  423. {: Returns the Maximum of an array of LongInts }
  424. function MaxLArray (const B: array of LongInt): LongInt;
  425.  
  426. {: Returns the Minimum of an array of Bytes }
  427. function MinBArray (const B: array of Byte): Byte;
  428.  
  429. {: Returns the Minimum of an array of Words }
  430. function MinWArray (const B: array of Word): Word;
  431.  
  432. {: Returns the Minimum of an array of ShortInts }
  433. function MinSIArray (const B: array of ShortInt): ShortInt;
  434.  
  435. {: Returns the Minimum of an array of Integers }
  436. function MinIArray (const B: array of Integer): Integer;
  437.  
  438. {: Returns the Minimum of an array of LongInts }
  439. function MinLArray (const B: array of LongInt): LongInt;
  440.  
  441. {: Returns the Sum of an array of Bytes. All Operation in Bytes }
  442. function SumBArray (const B: array of Byte): Byte;
  443.  
  444. {: Returns the Sum of an array of Bytes. All Operation in Words }
  445. function SumBArray2 (const B: array of Byte): Word;
  446.  
  447. {: Returns the Sum of an array of ShortInts. All Operation in ShortInts }
  448. function SumSIArray (const B: array of ShortInt): ShortInt;
  449.  
  450. {: Returns the Sum of an array of ShortInts. All Operation in Integers }
  451. function SumSIArray2 (const B: array of ShortInt): Integer;
  452.  
  453. {: Returns the Sum of an array of Words. All Operation in Words }
  454. function SumWArray (const B: array of Word): Word;
  455.  
  456. {: Returns the Sum of an array of Words. All Operation in Longints }
  457. function SumWArray2 (const B: array of Word): LongInt;
  458.  
  459. {: Returns the Sum of an array of Integers. All Operation in Integers }
  460. function SumIArray (const B: array of Integer): Integer;
  461.  
  462. {: Returns the Sum of an array of Longints. All Operation in Longints }
  463. function SumLArray (const B: array of LongInt): LongInt;
  464.  
  465. {: Returns the Sum of an array of LongWord. All Operation in LongWords }
  466. function SumLWArray (const B: array of LongWord): LongWord;
  467.  
  468. {: Returns the number of digits (Magnitude) of a Positive Integer}
  469. function ESBDigits (const X: LongWord): Byte;
  470.  
  471. {: Returns the highest Bit set within a LongWord. Donated by Michael Schnell }
  472. function BitsHighest (const X: LongWord): Integer;
  473.  
  474. {: Returns the number of Bits needed to represent a given positive integer}
  475. function ESBBitsNeeded (const X: LongWord): Integer;
  476.  
  477. {: Returns the Greatest Common (Positive) Divisor (GCD)of two Integers. Also
  478.     Refered to as the Highest Common Factor (HCF). Uses Euclid's Algorithm.
  479.      BASM Routine donated by Marcel Martin }
  480. function GCD (const X, Y: LongWord): LongWord;
  481.  
  482. {$IFDEF D4andAbove}
  483. {: Returns the Least Common Multiple of two Integers. }
  484. function LCM (const X, Y : LongInt): Int64;
  485. {$ELSE}
  486. {: Returns the Least Common Multiple of two Integers. }
  487. function LCM (const X, Y : LongInt): LongInt;
  488. {$ENDIF}
  489.  
  490. {: If two Integers are Relative Prime to each other then GCD (X, Y) = 1.
  491.     CoPrime is another term for Relative Prime. Some interpretive
  492.      problems may arise when '0' and/or '1' are used. }
  493. function RelativePrime (const X, Y: LongWord): Boolean;
  494.  
  495. {--- Floating Point Operations ---}
  496.  
  497. {: Returns the 80x87 Control Word <p>
  498.   15-12 Reserved  <p>
  499.     On 8087/80287 12 was Infinity Control <p>
  500.      0 Projective <p>
  501.      1 Affine <p>
  502.   11-10 Rounding Control <p>
  503.     00 Round to nearest even <p>
  504.     01 Round Down <p>
  505.     10 Round Up <p>
  506.     11 Chop - Truncate towards Zero <p>
  507.   9-8  Precision Control <p>
  508.     00 24 bits Single Precision <p>
  509.     01 Reserved <p>
  510.     10 53 bits Double Precision <p>
  511.     11 64 bits Extended Precision (Default) <p>
  512.   7-6  Reserved <p>
  513.     On 8087 7 was Interrupt Enable Mask <p>
  514.   5  Precesion Exception Mask <p>
  515.   4  Underflow Exception Mask <p>
  516.   3  Overflow Exception Mask <p>
  517.   2  Zero Divide Exception Mask <p>
  518.   1  Denormalised Operand Exception Mask <p>
  519.   0  Invalid Operation Exception Mask <p>
  520.   BASM }
  521. function Get87ControlWord: TBitList;
  522.  
  523. {: Sets the 80x87 Control Word <p>
  524.   15-12 Reserved <p>
  525.     On 8087/80287 12 was Infinity Control <p>
  526.      0 Projective <p>
  527.      1 Affine <p>
  528.   11-10 Rounding Control <p>
  529.     00 Round to nearest even <p>
  530.     01 Round Down <p>
  531.     10 Round Up <p>
  532.     11 Chop - Truncate towards Zero <p>
  533.   9-8  Precision Control <p>
  534.     00 24 bits Single Precision <p>
  535.     01 Reserved <p>
  536.     10 53 bits Double Precision <p>
  537.     11 64 bits Extended Precision (Default) <p>
  538.   7-6  Reserved <p>
  539.     On 8087 7 was Interrupt Enable Mask <p>
  540.   5  Precesion Exception Mask <p>
  541.   4  Underflow Exception Mask <p>
  542.   3  Overflow Exception Mask <p>
  543.   2  Zero Divide Exception Mask <p>
  544.   1  Denormalised Operand Exception Mask <p>
  545.   0  Invalid Operation Exception Mask <p>
  546.   BASM }
  547. procedure Set87ControlWord (const CWord: TBitList);
  548.  
  549. {: Swap two Extendeds. }
  550. procedure SwapExt (var X, Y: Extended);
  551.  
  552. {: Swap two Doubles. }
  553. procedure SwapDbl (var X, Y: Double);
  554.  
  555. {: Swap two Singles. }
  556. procedure SwapSing (var X, Y: Single);
  557.  
  558. {: Returns  <p>
  559.     -1 if X < 0 <p>
  560.      0 if X = 0 <p>
  561.      1 if X > 0 <p>
  562.  }
  563. function Sgn (const X: Extended): ShortInt;
  564.  
  565. {: Returns the straight line Distance between (X1, Y1) and (X2, Y2) }
  566. function Distance (const X1, Y1, X2, Y2: Extended): Extended;
  567.  
  568. {: Performs Floating Point Modulus. ExtMod := X - Floor ( X / Y ) * Y }
  569. function ExtMod (const X, Y: Extended): Extended;
  570.  
  571. {: Performs Floating Point Remainder. ExtRem := X - Int ( X / Y ) * Y }
  572. function ExtRem (const X, Y: Extended): Extended;
  573.  
  574. {: Returns X mod Y for Comp Data Types }
  575. function CompMOD (const X, Y: Comp): Comp;
  576.  
  577. {: Converts Polar Co-ordinates into Cartesion Co-ordinates }
  578. procedure Polar2XY (const Rho, Theta: Extended; var X, Y: Extended);
  579.  
  580. {: Converts Cartesian Co-ordinates to Polar Co-ordinates }
  581. procedure XY2Polar (const X, Y: Extended; var Rho, Theta: Extended);
  582.  
  583. {: Converts Degrees/Minutes/Seconds into an Extended Real }
  584. function DMS2Extended (const Degs, Mins, Secs: Extended): Extended;
  585.  
  586. {: Converts an Extended Real into Degrees/Minutes/Seconds }
  587. procedure Extended2DMS (const X: Extended; var Degs, Mins, Secs: Extended);
  588.  
  589. {: Returns the Maximum of two Extended Reals }
  590. function MaxExt (const X, Y: Extended): Extended;
  591.  
  592. {: Returns the Minimum of two Extended Reals }
  593. function MinExt (const X, Y: Extended): Extended;
  594.  
  595. {: Returns the Maximum of an array of Extended Reals }
  596. function MaxEArray (const B: array of Extended): Extended;
  597.  
  598. {: Returns the Minimum of an array of Extended Reals }
  599. function MinEArray (const B: array of Extended): Extended;
  600.  
  601. {: Returns the Maximum of an array of Single Reals }
  602. function MaxSArray (const B: array of Single): Single;
  603.  
  604. {: Returns the Maximum of an array of Single Reals }
  605. function MinSArray (const B: array of Single): Single;
  606.  
  607. {: Returns the Maximum of an array of Comp Reals }
  608. function MaxCArray (const B: array of Comp): Comp;
  609.  
  610. {: Returns the Minimum of an array of Comp Reals }
  611. function MinCArray (const B: array of Comp): Comp;
  612.  
  613. {: Returns the Sum of an Array of Single Reals }
  614. function SumSArray (const B: array of Single): Single;
  615.  
  616. {: Returns the Sum of an Array of Extended Reals }
  617. function SumEArray (const B: array of Extended): Extended;
  618.  
  619. {: Returns the Sum of the Square of an Array of Extended Reals }
  620. function SumSqEArray (const B: array of Extended): Extended;
  621.  
  622. {: Returns the Sum of the Square of the difference of
  623.     an Array of Extended Reals from a given Value }
  624. function SumSqDiffEArray (const B: array of Extended; Diff: Extended): Extended;
  625.  
  626. {: Returns the Sum of the Pairwise Product of two
  627.     Arrays of Extended Reals }
  628. function SumXYEArray (const X, Y: array of Extended): Extended;
  629.  
  630. {: Returns the Sum of an Array of Comp Reals }
  631. function SumCArray (const B: array of Comp): Comp;
  632.  
  633. {: Returns A! i.e Factorial of A - only values up to 1754 are handled
  634.     returns 0 if larger }
  635. function FactorialX (A: LongWord): Extended;
  636.  
  637. {: Returns nPr i.e Permutation of r objects from n.
  638.     Only values of N up to 1754 are handled    returns 0 if larger
  639.     If R > N  then 0 is returned }
  640. function PermutationX (N, R: LongWord): Extended;
  641.  
  642. {: Returns nCr i.e Combination of r objects from n.
  643.     These are also known as the Binomial Coefficients
  644.     Only values of N up to 1754 are handled    returns 0 if larger
  645.     If R > N  then 0 is returned }
  646.  
  647. function BinomialCoeff (N, R: LongWord): Extended;
  648.  
  649. {: Returns True if all elements of X > ESBTolerance }
  650. function IsPositiveEArray (const X: array of Extended): Boolean;
  651.  
  652. {: Returns the Geometric Mean of the values }
  653. function GeometricMean (const X: array of Extended): Extended;
  654.  
  655. {: Returns the Harmonic Mean of the values }
  656. function HarmonicMean (const X: array of Extended): Extended;
  657.  
  658. {: Returns the Arithmetic Mean of the Values }
  659. function ESBMean (const X: array of Extended): Extended;
  660.  
  661. {: Returns the Variance of the Values, assuming a Sample.
  662.     Square root this value to get Standard Deviation }
  663. function SampleVariance (const X: array of Extended): Extended;
  664.  
  665. {: Returns the Variance of the Values, assuming a Population.
  666.     Square root this value to get Standard Deviation }
  667. function PopulationVariance (const X: array of Extended): Extended;
  668.  
  669. {: Returns the Mean and Variance of the Values, assuming a Sample.
  670.     Square root the Variance to get Standard Deviation }
  671. procedure SampleVarianceAndMean (const X: array of Extended;
  672.     var Variance, Mean: Extended);
  673.  
  674. {: Returns the Mean and Variance of the Values, assuming a Population.
  675.     Square root the Variance to get Standard Deviation }
  676. procedure PopulationVarianceAndMean (const X: array of Extended;
  677.     var Variance, Mean: Extended);
  678.  
  679. {: Returns the Median (2nd Quartiles) of the Values. The array
  680.     MUST be sorted before using this operation }
  681. function GetMedian (const SortedX: array of Extended): Extended;
  682.  
  683. {: Returns the Mode (most frequent) of the Values. The array
  684.     MUST be sorted before using this operation. Function is False
  685.     if no Mode exists }
  686. function GetMode (const SortedX: array of Extended; var Mode: Extended): Boolean;
  687.  
  688. {: Returns the 1st and 3rd Quartiles - Median is 2nd Quartiles - of the Values.
  689.     The array    MUST be sorted before using this operation }
  690. procedure GetQuartiles (const SortedX: array of Extended; var Q1, Q3: Extended);
  691.  
  692. {: Returns the Magnitued of a given Value }
  693. function ESBMagnitude (const X: Extended): Integer;
  694.  
  695. {-- Trigonometric Functions ---}
  696.  
  697. //: Returns Tangent of Angle given in Radians.
  698. function ESBTan (Angle : Extended): Extended;
  699.  
  700. //: Returns CoTangent of the Angle given in Radians.
  701. function ESBCot (Angle : Extended): Extended;
  702.  
  703. //: Returns CoSecant of the Angle given in Radians.
  704. function ESBCosec (const Angle : Extended): Extended;
  705.  
  706. //: Returns Secant of the Angle given in Radians.
  707. function ESBSec (const Angle : Extended): Extended;
  708.  
  709. //: Returns the ArcTangent of Y / X - Result is in Radians
  710. function ESBArcTan (X, Y: Extended): Extended;
  711.  
  712. //: Fast Computation of Sin and Cos, where Angle is in Radians
  713. procedure ESBSinCos (Angle: Extended; var SinX, CosX: Extended);
  714.  
  715. //: Given a Value returns the Angle whose Cosine it is, in Radians
  716. function ESBArcCos (const X: Extended): Extended;
  717.  
  718. //: Given a Value returns the Angle whose Sine it is, in Radians
  719. function ESBArcSin (const X: Extended): Extended;
  720.  
  721. {: Given a Value returns the Angle whose Secant it is, in Radians.
  722. }
  723. function ESBArcSec (const X: Extended): Extended;
  724.  
  725. {: Given a Value returns the Angle whose Cosecant it is, in Radians.
  726. }
  727. function ESBArcCosec (const X: Extended): Extended;
  728.  
  729. {-- Logarithm & Power Functions ---}
  730.  
  731. //: Returns Logarithm of X to Base 10
  732. function ESBLog10 (const X: Extended): Extended;
  733.  
  734. //: Returns Logarithm of X to Base 2
  735. function ESBLog2 (const X: Extended): Extended;
  736.  
  737. //: Returns Logarithm of X to Given Base
  738. function ESBLogBase (const X, Base: Extended): Extended;
  739.  
  740. {: Calculate 2 to the given floating point power. Developed by Rory Daulton
  741.     and used with permission. December 1998.<p>
  742.     The algorithm used is to scale the power of the fractional part
  743.     of X, using FPU commands. Although the FPU (Floating Point Unit) is used,
  744.     the answer is exact for integral X, since the FSCALE FPU command is.<p>
  745.     EOverflow Exception when X > Log2(MaxExtended) = 11356.5234062941439494
  746.     (if there was no other FPU error condition, such as underflow or denormal,
  747.     before entry to this routine)<p>
  748.     EInvalidOp Exception on some occasions when EOverflow would be expected,
  749.     due to some other FPU error condition (such as underflow) before entry to
  750.     this routine.
  751. }
  752. function Pow2 (const X: Extended): Extended;
  753.  
  754. {: Calculate any float to non-negative integer power. Developed by Rory Daulton
  755.     and used with permission. Last modified December 1998.<p>
  756. }
  757. function IntPow (const Base: Extended; const Exponent: LongWord): Extended;
  758.  
  759. {: Raises Values to an Integer Power. Thanks to Rory Daulton for improvements.
  760. }
  761. function ESBIntPower (const X: Extended; const N: LongInt): Extended; 
  762.  
  763. //: Returns X^Y - handles all cases
  764. function XtoY (const X, Y: Extended): Extended;
  765.  
  766. //: Returns 10^Y - handles all cases
  767. function TenToY (const Y: Extended): Extended;
  768.  
  769. //: Returns 2^Y - handles all cases
  770. function TwoToY (const Y: Extended): Extended;
  771.  
  772. //: Returns log X using base Y - handles all valid cases
  773. function LogXtoBaseY (const X, Y: Extended): Extended;
  774.  
  775. {: ISqrt (I) computes INT (SQRT (I)), that is, the integral part of the
  776.     square root of integer I.
  777.     Code  originally developed by Marcel Martin, used with permission.
  778.     Rory Daulton introduced a faster routine (based on Marcel's) for most
  779.     occassions and this is now used with Permission.
  780. }
  781. function ISqrt (const I: LongWord): Longword;
  782.  
  783. {: Calculate the integer part of the logarithm base 2 of an integer.
  784.     Developed by Rory Daulton and used with Permission.<p>
  785.     An Exception is raised if I is Zero.
  786. }
  787. function ILog2 (const I: LongWord): LongWord;
  788.  
  789. {: Calculate the greatest integral power of two that is less than or equal to
  790.     the parameter.
  791.     EXCEPTIONS:  EInvalidArgument for argument zero.<P>
  792.     Developed By Rory Daulton - used with permission.
  793. }
  794. function IGreatestPowerOf2 (const N: LongWord): LongWord;
  795.  
  796. {--- Hyperbolic Functions ---}
  797.  
  798. //: Returns the inverse hyperbolic cosine of X
  799. function ESBArCosh (X : Extended) : Extended;
  800.  
  801. //: Returns the inverse hyperbolic sine of X
  802. function ESBArSinh (X : Extended) : Extended;
  803.  
  804. //: Returns the inverse hyperbolic tangent of X
  805. function ESBArTanh (X : Extended) : Extended;
  806.  
  807. //: Returns the hyperbolic cosine of X
  808. function ESBCosh (X : Extended) : Extended;
  809.  
  810. //: Returns the hyperbolic sine of X
  811. function ESBSinh (X : Extended) : Extended;
  812.  
  813. //: Returns the hyperbolic tangent of X
  814. function ESBTanh (X : Extended) : Extended;
  815.  
  816. {--- Special Functions ---}
  817.  
  818. {: Returns 1/Gamma(X) using a Series Expansion as defined in Abramowitz &
  819.     Stegun. Defined for all values of X.<p>
  820.     Accuracy: Gives about 15 digits.
  821. }
  822. function InverseGamma (const X: Extended): Extended;
  823.  
  824. {: Returns Gamma(X) using a Series Expansion for 1/Gamma (X) as defined in
  825.     Abramowitz & Stegun. Defined for all values of X except negative
  826.     integers and 0.<p>
  827.     Accuracy: Gives about 15 digits.
  828. }
  829. function Gamma (const X: Extended): Extended;
  830.  
  831. {: Logarithm to base e of the gamma function.
  832.     Accurate to about 1.e-14.
  833.     Programmer: Alan Miller - developed for Fortan 77, converted with permission.
  834. }
  835. function LnGamma (const X: Extended): Extended;
  836.  
  837. {: Returns Beta(X,Y) using a Series Expansion for 1/Gamma (X) as defined in
  838.     Abramowitz & Stegun. Defined for all values of X, Y except negative
  839.     integers and 0.
  840.     Accuracy: Gives about 15 digits.
  841. }
  842. function Beta (const X, Y: Extended): Extended;
  843.  
  844. {: Returns the Incomplete Beta Ix(P, Q), where 0 <= X <= 1 and
  845.     P and Q are positive.
  846.     Accuracy: Gives about 17 digits.<p>
  847.     Adapted From Collected Algorithms from CACM,
  848.     Algorithm 179 - Incomplete Beta Function Ratios,
  849.     Oliver G Ludwig.
  850. }
  851. function IncompleteBeta (X: Extended; P, Q: Extended): Extended;
  852.  
  853. implementation
  854.  
  855. uses
  856.     SysUtils;
  857.  
  858. procedure IncLim (var B: Byte; const Limit: Byte);
  859. begin
  860.     if B < Limit then
  861.         Inc (B);
  862. end;
  863.  
  864. procedure IncLimSI (var B: ShortInt; const Limit: ShortInt);
  865. begin
  866.     if B < Limit then
  867.         Inc (B);
  868. end;
  869.  
  870. procedure IncLimW (var B: Word; const Limit: Word);
  871. begin
  872.     if B < Limit then
  873.         Inc (B);
  874. end;
  875.  
  876. procedure IncLimI (var B: Integer; const Limit: Integer);
  877. begin
  878.     if B < Limit then
  879.         Inc (B);
  880. end;
  881.  
  882. procedure IncLimL (var B: LongInt; const Limit: LongInt);
  883. begin
  884.     if B < Limit then
  885.         Inc (B);
  886. end;
  887.  
  888. procedure DecLim (var B: Byte; const Limit: Byte);
  889. begin
  890.     if B > Limit then
  891.         Dec (B);
  892. end;
  893.  
  894. procedure DecLimSI (var B: ShortInt; const Limit: ShortInt);
  895. begin
  896.     if B > Limit then
  897.         Dec (B);
  898. end;
  899.  
  900. procedure DecLimW (var B: Word; const Limit: Word);
  901. begin
  902.     if B > Limit then
  903.         Dec (B);
  904. end;
  905.  
  906. procedure DecLimI (var B: Integer; const Limit: Integer);
  907. begin
  908.     if B > Limit then
  909.         Dec (B);
  910. end;
  911.  
  912. procedure DecLimL (var B: LongInt; const Limit: LongInt);
  913. begin
  914.     if B > Limit then
  915.         Dec (B);
  916. end;
  917.  
  918. function MaxB (const B1, B2: Byte): Byte;
  919. begin
  920.     if B1 > B2 then
  921.         Result := B1
  922.      else
  923.         Result := B2;
  924. end;
  925.  
  926. function MinB (const B1, B2: Byte): Byte;
  927. begin
  928.     if B1 < B2 then
  929.         Result := B1
  930.     else
  931.         Result := B2;
  932. end;
  933.  
  934. function MaxSI (const B1, B2: ShortInt): ShortInt;
  935. begin
  936.     if B1 > B2 then
  937.         Result := B1
  938.     else
  939.         Result := B2;
  940. end;
  941.  
  942. function MinSI (const B1, B2: ShortInt): ShortInt;
  943. begin
  944.     if B1 < B2 then
  945.         Result := B1
  946.     else
  947.         Result := B2;
  948. end;
  949.  
  950. function MaxW (const B1, B2: Word): Word;
  951. begin
  952.     if B1 > B2 then
  953.         Result := B1
  954.     else
  955.         Result := B2;
  956. end;
  957.  
  958. function MinW (const B1, B2: Word): Word;
  959. begin
  960.     if B1 < B2 then
  961.         Result := B1
  962.     else
  963.         Result := B2;
  964. end;
  965.  
  966. function MaxI (const B1, B2: Integer): Integer;
  967. begin
  968.     if B1 > B2 then
  969.         Result := B1
  970.     else
  971.         Result := B2;
  972. end;
  973.  
  974. function MinI (const B1, B2: Integer): Integer;
  975. begin
  976.     if B1 < B2 then
  977.         Result := B1
  978.     else
  979.         Result := B2;
  980. end;
  981.  
  982. function MaxL (const B1, B2: LongInt): LongInt;
  983. begin
  984.     if B1 > B2 then
  985.         Result := B1
  986.     else
  987.         Result := B2;
  988. end;
  989.  
  990. function MinL (const B1, B2: LongInt): LongInt;
  991. begin
  992.     if B1 < B2 then
  993.         Result := B1
  994.     else
  995.         Result := B2;
  996. end;
  997.  
  998. procedure SwapB (var B1, B2: Byte);
  999. var
  1000.     Temp: Byte;
  1001. begin
  1002.     Temp := B1;
  1003.     B1 := B2;
  1004.     B2 := Temp;
  1005. end;
  1006.  
  1007. procedure SwapSI (var B1, B2: ShortInt);
  1008. var
  1009.     Temp: ShortInt;
  1010. begin
  1011.     Temp := B1;
  1012.     B1 := B2;
  1013.     B2 := Temp;
  1014. end;
  1015.  
  1016. procedure SwapW (var B1, B2: Word);
  1017. var
  1018.     Temp: Word;
  1019. begin
  1020.     Temp := B1;
  1021.     B1 := B2;
  1022.     B2 := Temp;
  1023. end;
  1024. procedure SwapI (var B1, B2: SmallInt);
  1025. var
  1026.     Temp: SmallInt;
  1027. begin
  1028.     Temp := B1;
  1029.     B1 := B2;
  1030.     B2 := Temp;
  1031. end;
  1032.  
  1033. procedure SwapL (var B1, B2: LongInt);
  1034. var
  1035.     Temp: LongInt;
  1036. begin
  1037.     Temp := B1;
  1038.     B1 := B2;
  1039.     B2 := Temp;
  1040. end;
  1041.  
  1042. procedure SwapI32 (var B1, B2: Integer);
  1043. var
  1044.     Temp: Integer;
  1045. begin
  1046.     Temp := B1;
  1047.     B1 := B2;
  1048.     B2 := Temp;
  1049. end;
  1050.  
  1051. procedure SwapC (var B1, B2: LongWord);
  1052. var
  1053.     Temp: LongWord;
  1054. begin
  1055.     Temp := B1;
  1056.     B1 := B2;
  1057.     B2 := Temp;
  1058. end;
  1059.  
  1060. function Sign (const B: LongInt): ShortInt;
  1061. begin
  1062.     if B < 0 then
  1063.         Result := -1
  1064.     else if B = 0 then
  1065.         Result := 0
  1066.     else
  1067.         Result := 1;
  1068. end;
  1069.  
  1070. function Max4Word (const X1, X2, X3, X4: Word): Word;
  1071. begin
  1072.     Result := X1;
  1073.     if X2 > Result then
  1074.         Result := X2;
  1075.     if X3 > Result then
  1076.         Result := X3;
  1077.     if X4 > Result then
  1078.         Result := X4;
  1079. end;
  1080.  
  1081. function Min4Word (const X1, X2, X3, X4: Word): Word;
  1082. begin
  1083.     Result := X1;
  1084.     if X2 < Result then
  1085.         Result := X2;
  1086.     if X3 < Result then
  1087.         Result := X3;
  1088.     if X4 < Result then
  1089.         Result := X4;
  1090. end;
  1091.  
  1092. function Max3Word (const X1, X2, X3: Word): Word; 
  1093. begin
  1094.     Result := X1;
  1095.     if X2 > Result then
  1096.         Result := X2;
  1097.     if X3 > Result then
  1098.         Result := X3;
  1099. end;
  1100.  
  1101. function Min3Word (const X1, X2, X3: Word): Word; 
  1102. begin
  1103.     Result := X1;
  1104.     if X2 < Result then
  1105.         Result := X2;
  1106.     if X3 < Result then
  1107.         Result := X3;
  1108. end;
  1109.  
  1110. function MaxBArray (const B: array of Byte): Byte;
  1111. var
  1112.     I: Integer;
  1113. begin
  1114.     Result := B [Low (B)];
  1115.     for I:= Low (B) + 1 to High (B) do
  1116.         if B [I] > Result then
  1117.             Result := B [I];
  1118. end;
  1119.  
  1120. function MaxWArray (const B: array of Word): Word;
  1121. var
  1122.     I: Integer;
  1123. begin
  1124.     Result := B [Low (B)];
  1125.     for I:= Low (B) + 1 to High (B) do
  1126.         if B [I] > Result then
  1127.         Result := B [I];
  1128. end;
  1129.  
  1130. function MaxIArray (const B: array of Integer): Integer;
  1131. var
  1132.     I: Integer;
  1133. begin
  1134.     Result := B [Low (B)];
  1135.     for I:= Low (B) + 1 to High (B) do
  1136.         if B [I] > Result then
  1137.                Result := B [I];
  1138. end;
  1139.  
  1140. function MaxSIArray (const B: array of ShortInt): ShortInt;
  1141. var
  1142.      I: Integer;
  1143. begin
  1144.     Result := B [Low (B)];
  1145.     for I := Low (B) + 1 to High (B) do
  1146.     if B [I] > Result then
  1147.         Result := B [I];
  1148. end;
  1149.  
  1150. function MaxLArray (const B: array of LongInt): LongInt;
  1151. var
  1152.     I: Integer;
  1153. begin
  1154.     Result := B [Low (B)];
  1155.     for I := Low (B) + 1 to High (B) do
  1156.         if B [I] > Result then
  1157.             Result := B [I];
  1158. end;
  1159.  
  1160. function MinBArray (const B: array of Byte): Byte;
  1161. var
  1162.     I: Integer;
  1163. begin
  1164.     Result := B [Low (B)];
  1165.     for I := Low (B) + 1 to High (B) do
  1166.         if B [I] < Result then
  1167.            Result := B [I];
  1168. end;
  1169.  
  1170. function MinWArray (const B: array of Word): Word;
  1171. var
  1172.     I: Integer;
  1173. begin
  1174.     Result := B [Low (B)];
  1175.     for I := Low (B) + 1 to High (B) do
  1176.         if B [I] < Result then
  1177.               Result := B [I];
  1178. end;
  1179.  
  1180. function MinIArray (const B: array of Integer): Integer;
  1181. var
  1182.     I: Integer;
  1183. begin
  1184.     Result := B [Low (B)];
  1185.     for I := Low (B) + 1 to High (B) do
  1186.         if B [I] < Result then
  1187.              Result := B [I];
  1188. end;
  1189.  
  1190. function MinSIArray (const B: array of ShortInt): ShortInt;
  1191. var
  1192.     I: Integer;
  1193. begin
  1194.     Result := B [Low (B)];
  1195.     for I := Low (B) + 1 to High (B) do
  1196.         if B [I] < Result then
  1197.             Result := B [I];
  1198. end;
  1199.  
  1200. function MinLArray (const B: array of LongInt): LongInt;
  1201. var
  1202.     I: Integer;
  1203. begin
  1204.     Result := B [Low (B)];
  1205.     for I := Low (B) + 1 to High (B) do
  1206.         if B [I] < Result then
  1207.             Result := B [I];
  1208. end;
  1209.  
  1210. function ISqrt (const I: LongWord): LongWord;
  1211. const
  1212.     Estimates: array[0..31] of Word = (
  1213.     // for index i, constant := Trunc(Sqrt((Int64(2) shl i) - 1.0)), which is
  1214.     //   the largest possible ISqrt(n) for  2**i <= n < 2**(i+1)
  1215.         1,     1,     2,     3,     5,     7,    11,    15,
  1216.        22,    31,    45,    63,    90,   127,   181,   255,
  1217.       362,   511,   724,  1023,  1448,  2047,  2896,  4095,
  1218.      5792,  8191, 11585, 16383, 23170, 32767, 46340, 65535);
  1219.     // eax  // ebx  // ecx  // edx
  1220. asm  // entry:   // eax = I
  1221.   // calc the result quickly for zero or one (sqrt equals the argument)
  1222.        cmp     eax, 1
  1223.        jbe     @@end
  1224.   // save registers and the argument
  1225.        push    ebx
  1226.        mov     ebx, eax                // ebx = I
  1227.   // use the logarithm base 2 to load an initial estimate, which is greater
  1228.   //   than or equal to the actual value
  1229.        bsr     eax, ebx        // eax = ILog2(I) (note upper WORD is now zero)
  1230.        mov     ax, [word ptr Estimates + eax * 2]
  1231.                           // eax = X
  1232.   // repeat ...
  1233. @@repeat:
  1234.   // --  save the last estimate [ X ]
  1235.        mov     ecx, eax                        // ecx = X
  1236.   // --  calc the new estimate [ (I/X + X) / 2 ; the Newton-Raphson formula ]
  1237.        xor     edx, edx                                // edx = 0
  1238.        mov     eax, ebx        // eax = I (so edx:eax = I)
  1239.        div     ecx             // eax = I/X            // edx = I mod X
  1240.        add     eax, ecx        // eax = I/X + X
  1241.        shr     eax, 1          // eax = XNew = (I/X+X)/2
  1242.   // until the new estimate >= the last estimate
  1243.   //   [which can never happen in exact floating-point arithmetic, and can
  1244.   //   happen due to truncation only if the last estimate <= Sqrt(I) ]
  1245.        cmp     eax, ecx
  1246.        jb      @@repeat
  1247.   // use the next-to-last estimate as the result
  1248.        mov     eax, ecx        // eax = X
  1249.   // restore registers
  1250.        pop     ebx
  1251. @@end:              //exit:     // eax = Result
  1252. end {ISqrt};
  1253.  
  1254. function ILog2 (const I: LongWord): LongWord;
  1255.     procedure BadILog2;
  1256.     begin
  1257.         raise EMathError.Create('Division By Zero');
  1258.     end {BadILog2};
  1259. asm
  1260.     bsr     eax,eax
  1261.     jz      BadILog2
  1262. end {ILog2};
  1263.  
  1264. function SumBArray (const B: array of Byte): Byte;
  1265. var
  1266.     I: Integer;
  1267. begin
  1268.     Result := B [Low (B)];
  1269.     for I:= Low (B) + 1 to High (B) do
  1270.         Result := Result + B [I];
  1271. end;
  1272.  
  1273. function SumBArray2 (const B: array of Byte): Word;
  1274. var
  1275.     I: Integer;
  1276. begin
  1277.     Result := B [Low (B)];
  1278.     for I:= Low (B) + 1 to High (B) do
  1279.         Result := Result + B [I];
  1280. end;
  1281.  
  1282. function SumSIArray (const B: array of ShortInt): ShortInt;
  1283. var
  1284.     I: Integer;
  1285. begin
  1286.     Result := B [Low (B)];
  1287.     for I:= Low (B) + 1 to High (B) do
  1288.         Result := Result + B [I];
  1289. end;
  1290.  
  1291. function SumSIArray2 (const B: array of ShortInt): Integer;
  1292. var
  1293.     I: Integer;
  1294. begin
  1295.     Result := B [Low (B)];
  1296.     for I:= Low (B) + 1 to High (B) do
  1297.         Result := Result + B [I];
  1298. end;
  1299.  
  1300. function SumWArray (const B: array of Word): Word;
  1301. var
  1302.     I: Integer;
  1303. begin
  1304.     Result := B [Low (B)];
  1305.     for I:= 0 to High (B) do
  1306.         Result := Result + B [I];
  1307. end;
  1308.  
  1309. function SumWArray2 (const B: array of Word): LongInt;
  1310. var
  1311.     I: Integer;
  1312. begin
  1313.     Result := B [Low (B)];
  1314.     for I:= Low (B) + 1 to High (B) do
  1315.         Result := Result + B [I];
  1316. end;
  1317.  
  1318. function SumIArray (const B: array of Integer): Integer;
  1319. var
  1320.     I: Integer;
  1321. begin
  1322.     Result := B [Low (B)];
  1323.     for I:= Low (B) + 1 to High (B) do
  1324.         Result := Result + B [I];
  1325. end;
  1326.  
  1327. function SumLArray (const B: array of LongInt): LongInt;
  1328. var
  1329.     I: Integer;
  1330. begin
  1331.     Result := B [Low (B)];
  1332.     for I:= Low (B) + 1 to High (B) do
  1333.         Result := Result + B [I];
  1334. end;
  1335.  
  1336. function SumLWArray (const B: array of LongWord): LongWord;
  1337. var
  1338.     I: Integer;
  1339. begin
  1340.     Result := B [Low (B)];
  1341.     for I:= Low (B) + 1 to High (B) do
  1342.         Result := Result + B [I];
  1343. end;
  1344.  
  1345. function Get87ControlWord: TBitList; 
  1346. var
  1347.     Temp: Word;
  1348. asm
  1349.     fstcw [Temp]          { Get '87 Control Word }
  1350.     mov  ax, [Temp]     { Leave in AX for function }
  1351. end;
  1352.  
  1353. procedure Set87ControlWord (const CWord: TBitList);
  1354. var
  1355.     Temp: Word;
  1356. asm
  1357.     mov   [Temp], ax
  1358.     fldcw [Temp]         { Load '87 Control Word }
  1359. end;
  1360.  
  1361. procedure Polar2XY (const Rho, Theta: Extended; var X, Y: Extended);
  1362. begin
  1363.     ESBSinCos (Theta, Y, X); { quite fast }
  1364.     X := Rho * X;
  1365.     Y := Rho * Y;
  1366. end;
  1367.  
  1368. procedure XY2Polar (const X, Y: Extended; var Rho, Theta: Extended);
  1369. begin
  1370.     Rho := Sqrt (Sqr (X) + Sqr (Y));
  1371.     if Abs (X) > ESBTolerance then
  1372.     begin
  1373.         Theta := ArcTan (abs (Y) / abs (X));
  1374.         if Sgn (X) = 1 then
  1375.         begin
  1376.             if Sgn (Y) = -1 then
  1377.                 Theta := TwoPi - Theta
  1378.         end
  1379.         else
  1380.         begin
  1381.             if Sgn (Y) = 1 then
  1382.                 Theta := ESBPi - Theta
  1383.             else
  1384.                 Theta := ESBPi + Theta
  1385.         end;
  1386.     end
  1387.     else
  1388.         Theta := Sgn (Y) * Pion2
  1389. end;
  1390.  
  1391. function Sgn (const X: Extended): ShortInt;
  1392. begin
  1393.     if X < 0.0 then
  1394.         Result := -1
  1395.     else if X = 0.0 then
  1396.         Result := 0
  1397.     else
  1398.         Result := 1
  1399. end;
  1400.  
  1401. function DMS2Extended (const Degs, Mins, Secs: Extended): Extended;
  1402. begin
  1403.     Result := Degs + Mins / 60.0 + Secs / 3600.0
  1404. end;
  1405.  
  1406. procedure Extended2DMS (const X: Extended; var Degs, Mins, Secs: Extended);
  1407. var
  1408.     Y: Extended;
  1409. begin
  1410.     Degs := Int (X);
  1411.     Y := Frac (X) * 60;
  1412.     Mins := Int (Y);
  1413.     Secs := Frac (Y) * 60;
  1414. end;
  1415.  
  1416. function Distance (const X1, Y1, X2, Y2: Extended): Extended;
  1417. { Rory Daulton suggested this more tolerant routine }
  1418. var
  1419.     X, Y: Extended;
  1420. begin
  1421.     X := Abs (X1 - X2);
  1422.     Y := Abs (Y1 - Y2);
  1423.     if X > Y then
  1424.         Result := X * Sqrt (1 + Sqr (Y / X))
  1425.     else if Y <> 0 then
  1426.         Result := Y * Sqrt (1 + Sqr (X / Y))
  1427.     else
  1428.         Result := 0
  1429. end;
  1430.  
  1431. function ExtMod (const X, Y: Extended): Extended;
  1432. var
  1433.     Z: Extended;
  1434. begin
  1435.      Result := X / Y;
  1436.      Z := Int (Result);
  1437.      if Result < 0 then
  1438.         Z := Z - 1.0;
  1439.      { Z now has Floor (X / Y) }
  1440.      Result := X - Z * Y
  1441. end;
  1442.  
  1443. function ExtRem (const X, Y: Extended): Extended;
  1444. begin
  1445.     Result := X - Int (X / Y) * Y
  1446. end;
  1447.  
  1448. function MaxExt (const X, Y: Extended): Extended;
  1449. begin
  1450.     if X > Y then
  1451.         Result := X
  1452.     else
  1453.         Result := Y
  1454. end;
  1455.  
  1456. function MinExt (const X, Y: Extended): Extended;
  1457. begin
  1458.     if X < Y then
  1459.         Result := X
  1460.     else
  1461.         Result := Y
  1462. end;
  1463.  
  1464. function CompMOD (const X, Y: Comp): Comp;
  1465. begin
  1466.     Result := X - Y * Int (X / Y)
  1467. end;
  1468.  
  1469. function MaxEArray (const B: array of Extended): Extended;
  1470. var
  1471.     I: Integer;
  1472. begin
  1473.     Result := B [Low (B)];
  1474.     for I := Low (B) + 1 to High (B) do
  1475.         if B [I] > Result then
  1476.             Result := B [I];
  1477. end;
  1478.  
  1479. function MinEArray (const B: array of Extended): Extended;
  1480. var
  1481.     I: Integer;
  1482. begin
  1483.     Result := B [Low (B)];
  1484.     for I := Low (B) + 1 to High (B) do
  1485.     if B [I] < Result then
  1486.         Result := B [I];
  1487. end;
  1488.  
  1489. function MaxSArray (const B: array of Single): Single;
  1490. var
  1491.     I: Integer;
  1492. begin
  1493.     Result := B [Low (B)];
  1494.     for I := Low (B) + 1 to High (B) do
  1495.         if B [I] > Result then
  1496.             Result := B [I];
  1497. end;
  1498.  
  1499. function MinSArray (const B: array of Single): Single;
  1500. var
  1501.     I: Integer;
  1502. begin
  1503.     Result := B [Low (B)];
  1504.     for I := Low (B) + 1 to High (B) do
  1505.         if B [I] < Result then
  1506.               Result := B [I];
  1507. end;
  1508.  
  1509. function MaxCArray (const B: array of Comp): Comp;
  1510. var
  1511.     I: Integer;
  1512. begin
  1513.     Result := B [Low (B)];
  1514.     for I := Low (B) + 1 to High (B) do
  1515.         if B [I] > Result then
  1516.             Result := B [I];
  1517. end;
  1518.  
  1519. function MinCArray (const B: array of Comp): Comp;
  1520. var
  1521.     I: Integer;
  1522. begin
  1523.     Result := B [Low (B)];
  1524.     for I := Low (B) + 1 to High (B) do
  1525.         if B [I] < Result then
  1526.             Result := B [I];
  1527. end;
  1528.  
  1529. function SumSArray (const B: array of Single): Single;
  1530. var
  1531.     I: Integer;
  1532. begin
  1533.     Result := B [Low (B)];
  1534.     for I := Low (B) + 1 to High (B) do
  1535.         Result := Result + B [I];
  1536. end;
  1537.  
  1538. function SumEArray (const B: array of Extended): Extended;
  1539. var
  1540.     I: Integer;
  1541. begin
  1542.     Result := B [Low (B)];
  1543.     for I := Low (B) + 1 to High (B) do
  1544.         Result := Result + B [I];
  1545. end;
  1546.  
  1547. function SumSqEArray (const B: array of Extended): Extended;
  1548. var
  1549.     I: Integer;
  1550. begin
  1551.     Result := Sqr (B [Low (B)]);
  1552.     for I := Low (B) + 1 to High (B) do
  1553.         Result := Result + Sqr (B [I]);
  1554. end;
  1555.  
  1556. function SumSqDiffEArray (const B: array of Extended; Diff: Extended): Extended;
  1557. var
  1558.     I: Integer;
  1559. begin
  1560.     Result := Sqr (B [Low (B)] - Diff);
  1561.     for I := Low (B) + 1 to High (B) do
  1562.         Result := Result + Sqr (B [I] - Diff);
  1563. end;
  1564.  
  1565. function SumXYEArray (const X, Y: array of Extended): Extended;
  1566. var
  1567.     I: Integer;
  1568.     M, N: Integer;
  1569. begin
  1570.     M := MaxL (Low (X), Low (Y));
  1571.     N := MinL (High (X), High (Y));
  1572.     Result := X [M] * Y [M];
  1573.     for I := M + 1 to N do
  1574.         Result := Result + X [I] * Y [I];
  1575. end;
  1576.  
  1577. function SumCArray (const B: array of Comp): Comp;
  1578. var
  1579.     I: Integer;
  1580. begin
  1581.     Result := Low (B);
  1582.     for I := Low (B) + 1 to High (B) do
  1583.         Result := Result + B [I];
  1584. end;
  1585.  
  1586. function SameFloat (const X1, X2: Extended): Boolean;
  1587. begin
  1588.     Result := abs (X1 - X2) < ESBTolerance
  1589. end;
  1590.  
  1591. function FloatIsZero (const X: Extended): Boolean;
  1592. begin
  1593.     Result := abs (X) < ESBTolerance
  1594. end;
  1595.  
  1596. function FloatIsPositive (const X: Extended): Boolean;
  1597. begin
  1598.     Result := (X >= ESBTolerance);
  1599. end;
  1600.  
  1601. function FloatIsNegative (const X: Extended): Boolean;
  1602. begin
  1603.     Result := (X <= -ESBTolerance);
  1604. end;
  1605.  
  1606. function FactorialX (A: LongWord): Extended;
  1607. var
  1608.     I: Integer;
  1609. begin
  1610.     if A  > 1754 then
  1611.     begin
  1612.         Result := 0.0;
  1613.         Exit;
  1614.     end;
  1615.     Result := 1.0;
  1616.     for I := 2 to A do
  1617.         Result := Result * I;
  1618. end;
  1619.  
  1620. function PermutationX (N, R: LongWord): Extended;
  1621. var
  1622.     I : Integer;
  1623. begin
  1624.     if (N = 0) or (R > N) or (N > 1754) then
  1625.     begin
  1626.         Result := 0.0;
  1627.         Exit;
  1628.     end;
  1629.     Result := 1.0;
  1630.     if (R = 0) then
  1631.         Exit;
  1632.     try
  1633.         for I := N downto N - R + 1 do
  1634.             Result := Result * I;
  1635.         Result := Int (Result + 0.5);
  1636.     except
  1637.         Result := -1.0
  1638.     end;
  1639. end;
  1640.  
  1641. function BinomialCoeff (N, R: LongWord): Extended;
  1642. var
  1643.     I: Integer;
  1644.     K: LongWord;
  1645. begin
  1646.     if (N = 0) or (R > N) or (N > 1754) then
  1647.     begin
  1648.         Result := 0.0;
  1649.         Exit;
  1650.     end;
  1651.     Result := 1.0;
  1652.     if (R = 0) or (R = N) then
  1653.         Exit;
  1654.     if R > N div 2 then
  1655.         R := N - R;
  1656.     K := 2;
  1657.     try
  1658.         for I := N - R + 1 to N do
  1659.         begin
  1660.             Result := Result * I;
  1661.             if K <= R then
  1662.             begin
  1663.                 Result := Result / K;
  1664.                 Inc (K);
  1665.             end;
  1666.         end;
  1667.         Result := Int (Result + 0.5);
  1668.     except
  1669.         Result := -1.0
  1670.     end;
  1671. end;
  1672.  
  1673. function IsPositiveEArray (const X: array of Extended): Boolean;
  1674. var
  1675.     I: Integer;
  1676. begin
  1677.     Result := False;
  1678.     for I := 0 to High (X) do
  1679.         if X [I] <= ESBTolerance then
  1680.             Exit;
  1681.     Result := True;
  1682. end;
  1683.  
  1684. function GeometricMean (const X: array of Extended): Extended;
  1685. var
  1686.     I: Integer;
  1687. begin
  1688.     if High (X) < 0 then
  1689.         raise Exception.Create ('Array is Empty!')
  1690.     else if not IsPositiveEArray (X) then
  1691.         raise Exception.Create ('Array contains values <= 0!')
  1692.     else
  1693.     begin
  1694.         Result := 1;
  1695.         for I := 0 to High (X) do
  1696.             Result := Result * X [I];
  1697.         Result := XtoY (Result, 1 / (High (X) + 1));
  1698.     end;
  1699. end;
  1700.  
  1701. function HarmonicMean (const X: array of Extended): Extended;
  1702. var
  1703.     I: Integer;
  1704. begin
  1705.     if High (X) < 0 then
  1706.         raise Exception.Create ('Array is Empty!')
  1707.     else if not IsPositiveEArray (X) then
  1708.         raise Exception.Create ('Array contains values <= 0!')
  1709.     else
  1710.     begin
  1711.         Result := 0;
  1712.         for I := 0 to High (X) do
  1713.             Result := Result + 1 / X [I];
  1714.         Result := Result / (High (X) + 1);
  1715.         Result := 1 / Result;
  1716.     end;
  1717. end;
  1718.  
  1719. function ESBMean (const X: array of Extended): Extended;
  1720. begin
  1721.     Result := SumEArray (X) / (High (X) - Low (X) + 1)
  1722. end;
  1723.  
  1724. function SampleVariance (const X: array of Extended): Extended;
  1725. var
  1726.     I: Integer;
  1727.     SumSq: Extended;
  1728.     Mean: Extended;
  1729. begin
  1730.     Mean := ESBMean (X);
  1731.     SumSq := 0.0;
  1732.     for I := Low (X) to High (X) do
  1733.         SumSq := SumSq + Sqr (X [I] - Mean);
  1734.     Result := SumSq / (High (X) - Low (X))
  1735. end;
  1736.  
  1737. function PopulationVariance (const X: array of Extended): Extended;
  1738. var
  1739.     I: Integer;
  1740.     SumSq: Extended;
  1741.     Mean: Extended;
  1742. begin
  1743.     Mean := ESBMean (X);
  1744.     SumSq := 0.0;
  1745.     for I := Low (X) to High (X) do
  1746.         SumSq := SumSq + Sqr (X [I] - Mean);
  1747.     Result := SumSq / (High (X) - Low (X) + 1)
  1748. end;
  1749.  
  1750. procedure SampleVarianceAndMean (const X: array of Extended;
  1751.     var Variance, Mean: Extended);
  1752. var
  1753.     I: Integer;
  1754.     SumSq: Extended;
  1755. begin
  1756.     Mean := ESBMean (X);
  1757.     SumSq := 0.0;
  1758.     for I := Low (X) to High (X) do
  1759.         SumSq := SumSq + Sqr (X [I] - Mean);
  1760.     if High (X) > Low (X) then
  1761.         Variance := SumSq / (High (X) - Low (X))
  1762.     else
  1763.         Variance := 0;
  1764. end;
  1765.  
  1766. procedure PopulationVarianceAndMean (const X: array of Extended;
  1767.     var Variance, Mean: Extended);
  1768. var
  1769.     I: Integer;
  1770.     SumSq: Extended;
  1771. begin
  1772.     Mean := ESBMean (X);
  1773.     SumSq := 0.0;
  1774.     for I := Low (X) to High (X) do
  1775.         SumSq := SumSq + Sqr (X [I] - Mean);
  1776.     Variance := SumSq / (High (X) - Low (X) + 1)
  1777. end;
  1778.  
  1779. function GetMedian (const SortedX: array of Extended): Extended;
  1780. var
  1781.     N: Integer;
  1782. begin
  1783.     N := High (SortedX) + 1;
  1784.     if N <= 0 then
  1785.         raise Exception.Create ('Array is Empty!')
  1786.     else if N = 1 then
  1787.         Result := SortedX [0]
  1788.     else if Odd (N) then
  1789.         Result := SortedX [N div 2]
  1790.     else
  1791.         Result := (SortedX [N div 2 - 1] + SortedX [N div 2]) / 2;
  1792. end;
  1793.  
  1794. function GetMode (const SortedX: array of Extended; var Mode: Extended): Boolean;
  1795. var
  1796.     I, Freq, HiFreq: Integer;
  1797.     Matched: Boolean;
  1798. begin
  1799.     if High (SortedX) < 0 then
  1800.     begin
  1801.         raise Exception.Create ('Array is Empty!')
  1802.     end
  1803.     else if High (SortedX) = 0 then
  1804.     begin
  1805.         Mode := SortedX [0];
  1806.         Result := True;
  1807.     end
  1808.     else
  1809.     begin
  1810.         Mode := -MaxExtended;
  1811.         Freq := 1;
  1812.         HiFreq := 0;
  1813.         Matched := False;
  1814.         for I := 1 to High (SortedX) do
  1815.         begin
  1816.             if SameFloat (SortedX [I - 1], SortedX [I]) then
  1817.                 Inc (Freq)
  1818.             else
  1819.             begin
  1820.                 if Freq <> 1 then
  1821.                 begin
  1822.                     if Freq = HiFreq then
  1823.                         Matched := True
  1824.                     else if Freq > HiFreq then
  1825.                     begin
  1826.                         Mode := SortedX [I - 1];
  1827.                         HiFreq := Freq;
  1828.                         Matched := False;
  1829.                     end;
  1830.                     Freq := 1;
  1831.                 end;
  1832.             end;
  1833.         end;
  1834.         if HiFreq > 0 then
  1835.         begin
  1836.             if Freq = HiFreq then
  1837.                 Matched := True
  1838.             else if Freq > HiFreq then
  1839.             begin
  1840.                 Mode := SortedX [High (SortedX)];
  1841.                 Matched := False;
  1842.             end;
  1843.         end
  1844.         else if Freq > 1 then
  1845.         begin
  1846.             HiFreq := Freq;
  1847.             Mode := SortedX [High (SortedX)];
  1848.             Matched := False;
  1849.         end;
  1850.         Result := (HiFreq > 0) and not Matched;
  1851.     end;
  1852. end;
  1853.  
  1854. procedure GetQuartiles (const SortedX: array of Extended; var Q1, Q3: Extended);
  1855. var
  1856.     N: Single;
  1857.     I: Integer;
  1858. begin
  1859.     if High (SortedX) < 0 then
  1860.         raise Exception.Create ('Array is Empty!')
  1861.     else if High (SortedX) = 0 then
  1862.     begin
  1863.         Q1 := SortedX [0];
  1864.         Q3 := SortedX [0];
  1865.     end
  1866.     else
  1867.     begin
  1868.         N := (High (SortedX) + 1) / 4 + 0.5;
  1869.         I := Trunc (N);
  1870.         N := Frac (N);
  1871.         if I - 1 < High (SortedX) then
  1872.             Q1 := SortedX [I - 1] + (SortedX [I] - SortedX [I - 1]) * N
  1873.         else
  1874.             Q1 := SortedX [I - 1];
  1875.  
  1876.         N := 3 * (High (SortedX) + 1) / 4 + 0.5;
  1877.         I := Trunc (N);
  1878.         N := Frac (N);
  1879.         if I - 1 < High (SortedX) then
  1880.             Q3 := SortedX [I - 1] + (SortedX [I] - SortedX [I - 1]) * N
  1881.         else
  1882.             Q3 := SortedX [I - 1];
  1883.     end;
  1884. end;
  1885.  
  1886. function ESBDigits (const X: LongWord): Byte;
  1887. // Returns the number of digits in a given positive integer
  1888. begin
  1889.     if X = 0 then
  1890.         Result := 0
  1891.     else
  1892.         Result := Trunc (ESBLog10 (X)) + 1;
  1893. end;
  1894.  
  1895. function ESBMagnitude (const X: Extended): Integer;
  1896. // Returns the number of digits in a given positive integer
  1897. begin
  1898.     if X = 0 then
  1899.         Result := 0
  1900.     else
  1901.     begin
  1902.         if X >= 1 then
  1903.             Result := Trunc (ESBLog10 (Abs (X))) + 1
  1904.         else
  1905.             Result := Trunc (ESBLog10 (Abs (X)) - 0.00000000001) - 1
  1906.     end;
  1907. end;
  1908.  
  1909. function BitsHighest (const X: LongWord): Integer;
  1910. asm
  1911.        MOV     ECX, EAX
  1912.        MOV     EAX, -1
  1913.        BSR     EAX, ECX
  1914. end;
  1915.  
  1916. function ESBBitsNeeded (const X: LongWord): Integer;
  1917. begin
  1918.     Result := BitsHighest (X) + 1;
  1919. end;
  1920.  
  1921.  
  1922. {--- Trigonometric Functions ---}
  1923.  
  1924. function ESBTan (Angle : Extended): Extended;
  1925.     function FTan (Angle : Extended): Extended;
  1926.     asm
  1927.         fld        [Angle]    // St(0) <- Angle
  1928.         ffree     st(7)    // Ensure st(7) is free
  1929.         fptan             // St(1) <- Tan (Angle), St(0) <- 1
  1930.         fstp        st(0)    // Dispose of 1
  1931.         fwait
  1932.     end;
  1933. begin
  1934.     if abs (Angle) >= TwoToPower63 then // must be less then 2^63
  1935.         raise EMathError.Create ('Angle Magnitude too large for ESBTan')
  1936.     else
  1937.         Result := FTan (Angle);
  1938. end;
  1939.  
  1940. function ESBCot (Angle : Extended): Extended;
  1941.     function FCot (Angle : Extended): Extended;
  1942.     asm
  1943.         fld        [Angle]    // St(0) <- Angle
  1944.         ffree     st(7)    // Ensure st(7) is free
  1945.         fptan             // St(1) <- Tan (Angle), St(0) <- 1
  1946.         fdivrp            // St(0) <- St(0)/St(1) which is Cot
  1947.         fwait
  1948.     end;
  1949. begin
  1950.     if abs (Angle) >= TwoToPower63 then // must be less then 2^63
  1951.         raise EMathError.Create ('Angle Magnitude too large for ESBCot')
  1952.     else
  1953.         Result := FCot (Angle);
  1954. end;
  1955.  
  1956. function ESBArcTan (X, Y: Extended): Extended;
  1957.     function FArcTan (X, Y: Extended): Extended;
  1958.     asm
  1959.         fld        [Y]        // St(0) <- Y
  1960.         fld         [X]        // St(0) <- X, St (1) <- Y
  1961.         fpatan            // St(0) <- ArcTan (Y/X)
  1962.         fwait
  1963.     end;
  1964. begin
  1965.     if X = 0 then
  1966.      begin
  1967.          if Y = 0 then
  1968.               Result := 0
  1969.           else if Y > 0 then
  1970.               Result := PiOn2
  1971.           else
  1972.               Result := - PiOn2
  1973.      end
  1974.      else if Y = 0 then
  1975.     begin
  1976.         if X > 0 then
  1977.             Result := 0
  1978.         else
  1979.             Result := ESBPi
  1980.     end
  1981.     else
  1982.         Result := FArcTan (X, Y);
  1983. end;
  1984.  
  1985. procedure ESBSinCos (Angle: Extended; var SinX, CosX: Extended);
  1986.     procedure FSinCos (Angle: Extended; var SinX, CosX: Extended);
  1987.     asm
  1988.         fld        [Angle]            // St(0) <- Angle
  1989.         fsincos
  1990.         fstp        tbyte ptr [edx]    // St(0) -> CosX
  1991.         fstp        tbyte ptr [eax]    // St(0) -> SinX
  1992.         fwait
  1993.     end;
  1994. begin
  1995.     if abs (Angle) >= TwoToPower63 then // must be less then 2^63
  1996.         raise EMathError.Create ('Angle Magnitude too large for ESBSinCos')
  1997.     else
  1998.         FSinCos (Angle, SinX, CosX);
  1999. end;
  2000.  
  2001. function ESBArcCos (const X: Extended): Extended;
  2002. var
  2003.     Y: Extended;
  2004. begin
  2005.     if abs (X) > 1 then
  2006.         raise EMathError.Create ('ESBArcCos requires values with magnitude <= 1')
  2007.     else
  2008.     begin
  2009.         Y := Sqrt (1 - Sqr (X));
  2010.         if abs (X) <= Y then
  2011.             Result := PiOn2 - ESBArcTan (Y, X)
  2012.         else    if X < 0 then
  2013.             Result := ESBArcTan (X, Y) + ESBPi
  2014.         else
  2015.             Result := ESBArcTan (X, Y)
  2016.     end;
  2017. end;
  2018.  
  2019. function ESBArcSin (const X: Extended): Extended;
  2020. var
  2021.     Y: Extended;
  2022. begin
  2023.     if abs (X) > 1 then
  2024.         raise EMathError.Create ('ESBArcSin requires values with magnitude <= 1')
  2025.     else
  2026.     begin
  2027.         Y := Sqrt (1 - Sqr (X));
  2028.         if abs (X) <= Y then
  2029.             Result :=  ESBArcTan (Y, X)
  2030.         else
  2031.             Result := Sgn (X) * PiOn2 - ESBArcTan (X, Y)
  2032.     end;
  2033. end;
  2034.  
  2035. function ESBCosec (const Angle: Extended): Extended;
  2036. var
  2037.     Y: Extended;
  2038. begin
  2039.     Y := Sin (Angle);
  2040.     if Y = 0 then
  2041.         raise EMathError.Create ('ESBCosec is Undefined')
  2042.     else
  2043.         Result := 1 / Y;
  2044. end;
  2045.  
  2046. function ESBSec (const Angle: Extended): Extended;
  2047. var
  2048.     Y: Extended;
  2049. begin
  2050.     Y := Cos (Angle);
  2051.     if Y = 0 then
  2052.         raise EMathError.Create ('ESBSec is Undefined')
  2053.     else
  2054.         Result := 1 / Y;
  2055. end;
  2056.  
  2057. function ESBArcSec (const X: Extended): Extended;
  2058. begin
  2059.     if FloatIsZero (X) then
  2060.         raise EMathError.Create ('Divide By Zero');
  2061.     Result := ESBArcCos (1 / Abs (X));
  2062.     if X < 0 then
  2063.         Result := Result + ESBPI;
  2064. end;
  2065.  
  2066. function ESBArcCosec (const X: Extended): Extended;
  2067. begin
  2068.     if FloatIsZero (X) then
  2069.         raise EMathError.Create ('Divide By Zero');
  2070.     Result := ESBArcSin (1 / Abs (X));
  2071.     if X < 0 then
  2072.         Result := Result + ESBPI;
  2073. end;
  2074.  
  2075. {--- Logarithm & Power Functions ---}
  2076.  
  2077. {------------------------------------------------------------------------------
  2078. PURPOSE:     Calculate 2 to the given floating point power.
  2079. AUTHOR:      Rory Daulton
  2080. DATE:        December 1998
  2081. PARAMETERS:  X: power to take of 2 [so the result is 2**X]
  2082. EXCEPTIONS:  EOverflow  when X > Log2(MaxExtended) = 11356.5234062941439494
  2083.                     (if there was no other FPU error condition, such as
  2084.                     underflow or denormal, before entry to this routine)
  2085.            EInvalidOp on some occasions when EOverflow would be expected, due
  2086.                     to some other FPU error condition (such as underflow)
  2087.                     before entry to this routine
  2088. NOTES:       1. The algorithm used is to scale the power of the fractional part
  2089.              of X, using FPU commands.
  2090.            2. Although the FPU (Floating Point Unit) is used, the answer is
  2091.              exact for integral X, since the FSCALE FPU command is.
  2092. ------------------------------------------------------------------------------}
  2093. function Pow2 (const X: Extended): Extended;
  2094. asm
  2095.        fld     X
  2096. // find Round(X)
  2097.        fld     st
  2098.        frndint
  2099. // find _Frac(X) [minimal fractional part of X, between -0.5 and 0.5]
  2100.        fsub    st(1),st
  2101.        fxch    st(1)
  2102. // Find 2**_Frac(X)
  2103.        f2xm1
  2104.        fld1
  2105.        fadd
  2106. // Result := 2**_Frac(X) * 2**Round(X)
  2107.        fscale
  2108.        fstp    st(1)
  2109.        fwait
  2110. end {Pow2};
  2111.  
  2112. function IntPow (const Base: Extended; const Exponent: LongWord): Extended;
  2113.   { Heart of Rory Daulton's IntPower: assumes valid parameters &
  2114.     non-negative exponent }
  2115. asm
  2116.         fld1                      { Result := 1 }
  2117.         cmp     eax, 0            { eax := Exponent }
  2118.         jz      @@3
  2119.         fld     Base
  2120.         jmp     @@2
  2121.   @@1:    fmul    ST, ST            { X := Base * Base }
  2122.   @@2:    shr     eax,1
  2123.         jnc     @@1
  2124.         fmul    ST(1),ST          { Result := Result * X }
  2125.         jnz     @@1
  2126.         fstp    st                { pop X from FPU stack }
  2127.   @@3:
  2128.         fwait
  2129.   end {P};
  2130.  
  2131.  
  2132. function ESBLog10 (const X: Extended): Extended;
  2133.     function FLog10 (X: Extended): Extended;
  2134.     asm
  2135.         fldlg2            // St(0) <- Log10 of 2
  2136.         fld        [X]        // St(0) <- X, St(1) <- Log10 of 2
  2137.         fyl2x            // St(0) <- log10 (2) * Log2 (X)
  2138.         fwait
  2139.     end;
  2140.     function AltFLog10 (X: Extended): Extended;
  2141.     asm
  2142.         fldlg2            // St(0) <- Log10 of 2
  2143.         fld        [X]        // St(0) <- X, St(1) <- Log10 of 2
  2144.         fyl2xp1            // St(0) <- log10 (2) * Log2 (X+1)
  2145.         fwait
  2146.     end;
  2147. begin
  2148.     if not FloatIsPositive (X) then // must be Positive
  2149.         raise EMathError.Create ('Value must be > 0')
  2150.     else if abs (X - 1) < 0.1 then
  2151.         Result := AltFLog10 (X - 1)
  2152.     else
  2153.         Result := FLog10 (X);
  2154. end;
  2155.  
  2156. function ESBLog2 (const X: Extended): Extended;
  2157.     function FLog2 (X: Extended): Extended;
  2158.     asm
  2159.         fld1                // St(0) <- 1
  2160.         fld        [X]        // St(0) <- X, St(1) <-1
  2161.         fyl2x            // St(0) <- 1 * Log2 (X)
  2162.         fwait
  2163.     end;
  2164.     function AltFLog2 (X: Extended): Extended;
  2165.     asm
  2166.         fld1                // St(0) <- 1
  2167.         fld        [X]        // St(0) <- X, St(1) <-1
  2168.         fyl2xp1            // St(0) <- 1 * Log2 (X+1)
  2169.         fwait
  2170.     end;
  2171. begin
  2172.     if not FloatIsPositive (X) then // must be Positive
  2173.         raise EMathError.Create ('Value must be > 0')
  2174.     else if abs (X - 1) < 0.1 then
  2175.         Result := AltFLog2 (X - 1)
  2176.     else
  2177.         Result := FLog2 (X);
  2178. end;
  2179.  
  2180. function ESBLogBase (const X, Base: Extended): Extended;
  2181. begin
  2182.     if not FloatIsPositive (X) then // must be Positive
  2183.         raise EMathError.Create ('Value must be > 0')
  2184.     else if not FloatIsPositive (Base) then // must be Positive
  2185.         raise EMathError.Create ('Value must be > 0')
  2186.     else
  2187.         Result := ESBLog2 (X) / ESBLog2 (Base);
  2188. end;
  2189.  
  2190. function LogXtoBaseY (const X, Y: Extended): Extended;
  2191. begin
  2192.     Result := ESBLog2 (X) / ESBLog2 (Y);
  2193. end;
  2194.  
  2195. function ESBIntPower (const X: Extended; const N: LongInt): Extended;
  2196. var
  2197.     P: LongWord;
  2198. begin
  2199.     if N = 0 then
  2200.         Result := 1
  2201.     else if (X = 0) then
  2202.     begin
  2203.         if N < 0 then
  2204.             raise EMathError.Create ('Zero cannot be raised to a Negative Power')
  2205.         else
  2206.             Result := 0
  2207.     end
  2208.     else if (X = 1) then
  2209.         Result := 1
  2210.     else if X = -1 then
  2211.     begin
  2212.         if Odd (N) then
  2213.             Result := -1
  2214.         else
  2215.             Result := 1
  2216.     end
  2217.     else if N > 0 then
  2218.         Result := IntPow (X, N)
  2219.     else
  2220.     begin
  2221.         if N <> Low (LongInt) then
  2222.             P := abs (N)
  2223.         else
  2224.             {$IFDEF D4andAbove}
  2225.             P := LongWord (High (LongInt)) + 1;
  2226.             {$Else}
  2227.             raise EMathError.Create ('Cannot be raised to Low (LongInt)');
  2228.             {$ENDIF}
  2229.         try
  2230.             Result := IntPow (X, P);
  2231.         except
  2232.             on EMathError do
  2233.             begin
  2234.                 Result := IntPow (1 / X, P); { try again with another method, }
  2235.                 Exit;                           {   perhaps less precise         }
  2236.             end {on};
  2237.         end {try};
  2238.         Result := 1 / Result;
  2239.     end;
  2240. end;
  2241.  
  2242. function XtoY (const X, Y: Extended): Extended;
  2243.     function PowerAbs: Extended; // Routine developed by Rory Daulton
  2244.     var
  2245.         ExponentPow2: Extended; // equivalent exponent to power 2
  2246.     begin
  2247.         try
  2248.             ExponentPow2 := ESBLog2 (Abs (X)) * Y;
  2249.         except
  2250.             on EMathError do
  2251.                // allow underflow, when ExponentPow2 would have been negative
  2252.                 if (Abs (X) > 1) <> (Y > 0) then
  2253.                 begin
  2254.                     Result := 0;
  2255.                     Exit;
  2256.                 end {if}
  2257.                 else
  2258.                     raise;
  2259.         end {try};
  2260.         Result := Pow2 (ExponentPow2);
  2261.     end;
  2262. begin
  2263.     if FloatIsZero (Y) then
  2264.         Result := 1
  2265.     else if FloatIsZero (X) then
  2266.     begin
  2267.         if Y < 0 then
  2268.             raise EMathError.Create ('Zero cannot be raised to a Negative Power')
  2269.         else
  2270.             Result := 0
  2271.     end
  2272.     else if FloatIsZero (Frac (Y)) then
  2273.     begin
  2274.         if (Y >= Low (LongInt)) and (Y <= High (LongInt)) then
  2275.             Result := ESBIntPower (X, LongInt (Round (Y)))
  2276.         else
  2277.         begin
  2278.             if (X > 0) or FloatIsZero (Frac (Y / 2.0)) then
  2279.                 Result := PowerAbs
  2280.             else
  2281.                 Result := -PowerAbs
  2282.         end;
  2283.     end
  2284.     else if X > 0 then
  2285.         Result := PowerAbs
  2286.     else
  2287.         raise EMathError.Create ('Invalid X^Y')
  2288. end;
  2289.  
  2290. function TenToY (const Y: Extended): Extended;
  2291. begin
  2292.     if FloatIsZero (Y) then
  2293.         Result := 1
  2294.     else if Y < -3.58e4931 then
  2295.         Result := 0
  2296.     else
  2297.         Result := Pow2 (Y * Log10Base2)
  2298. end;
  2299.  
  2300. function TwoToY (const Y: Extended): Extended;
  2301. begin
  2302.     if FloatIsZero (Y) then
  2303.         Result := 1
  2304.     else
  2305.         Result := Pow2 (Y)
  2306. end;
  2307.  
  2308. {--- Hyperbolic Functions ---}
  2309.  
  2310. function ESBArCosh (X: Extended): Extended;
  2311. begin
  2312.     Result := Ln (X + Sqrt (Sqr (X) - 1));
  2313. end;
  2314.  
  2315. function ESBArSinh (X: Extended): Extended;
  2316. begin
  2317.     Result := Ln (X + Sqrt (Sqr (X) + 1));
  2318. end;
  2319.  
  2320. function ESBArTanh (X: Extended): Extended;
  2321. var
  2322.     Y: Extended;
  2323. begin
  2324.     if X = 1 then
  2325.         raise EMathError.Create ('ESBArTanh is not Defined for X = 1')
  2326.     else
  2327.     begin
  2328.         Y :=(1 + X) / (1 - X);
  2329.         if Y <= 0 then
  2330.             raise EMathError.Create ('ESBArTanh is not Defined for that Value of X')
  2331.         else
  2332.             Result := Ln (Y) / 2;
  2333.     end;
  2334. end;
  2335.  
  2336. function ESBCosh (X: Extended): Extended;
  2337. begin
  2338.     Result := (Exp (X) + Exp (-X)) / 2.0;
  2339. end;
  2340.  
  2341. function ESBSinh (X: Extended): Extended;
  2342. begin
  2343.     Result := (Exp (X) - Exp (-X)) / 2.0;
  2344. end;
  2345.  
  2346. function ESBTanh (X: Extended): Extended;
  2347. var
  2348.     Y: Extended;
  2349. begin
  2350.     Y := ESBCosh (X);
  2351.     if Y = 0 then
  2352.         raise EMathError.Create ('X has a Cosh of 0, illegal for ESBTanh')
  2353.     else
  2354.         Result := ESBSinh (X) / Y;
  2355. end;
  2356.  
  2357. function GCD (const X, Y: LongWord): LongWord;
  2358. asm
  2359.      jmp   @01      // We start with EAX <- X, EDX <- Y, and check to see if Y = 0
  2360. @00: mov   ecx, edx    // ECX <- EDX prepare for division
  2361.      xor   edx, edx // clear EDX for Division
  2362.      div   ecx        // EAX <- EDX:EAX div ECX, EDX <- EDX:EAX mod ECX
  2363.      mov   eax, ecx    // EAX <- ECX, and repeat if EDX <> 0
  2364. @01: and   edx, edx // test to see if EDX is zero, without changing EDX
  2365.      jnz   @00        // when EDX is zero EAX has the result
  2366. end;
  2367.  
  2368. {$IFDEF D4andAbove}
  2369. function LCM (const X, Y : LongInt): Int64;
  2370. begin
  2371.     Result:= (X div LongInt (GCD (Abs (X), Abs (Y)))) * Int64 (Y);
  2372. end;
  2373. {$ELSE}
  2374. function LCM (const X, Y : LongInt): LongInt;
  2375. begin
  2376.     Result:= (X div LongInt (GCD (Abs (X), Abs (Y)))) * Y;
  2377. end;
  2378. {$ENDIF}
  2379.  
  2380. function RelativePrime (const X, Y: LongWord): Boolean;
  2381. begin
  2382.     Result := GCD (X, Y) = 1;
  2383. end;
  2384.  
  2385. {$IFDEF D4andAbove}
  2386. procedure SwapInt64 (var X, Y: Int64);
  2387. var
  2388.     Temp: Int64;
  2389. begin
  2390.     Temp := X;
  2391.     X := Y;
  2392.     Y := Temp;
  2393. end;
  2394. {$ENDIF}
  2395.  
  2396. procedure SwapExt (var X, Y: Extended);
  2397. var
  2398.     Temp: Extended;
  2399. begin
  2400.     Temp := X;
  2401.     X := Y;
  2402.     Y := Temp;
  2403. end;
  2404.  
  2405. procedure SwapDbl (var X, Y: Double);
  2406. var
  2407.     Temp: Double;
  2408. begin
  2409.     Temp := X;
  2410.     X := Y;
  2411.     Y := Temp;
  2412. end;
  2413.  
  2414. procedure SwapSing (var X, Y: Single);
  2415. var
  2416.     Temp: Single;
  2417. begin
  2418.     Temp := X;
  2419.     X := Y;
  2420.     Y := Temp;
  2421. end;
  2422.  
  2423. {$IFDEF D4andAbove}
  2424. {---------------------------------------------------------------------------
  2425. ---
  2426. PURPOSE: Show an unsigned-integer overflow error with an exception
  2427. NOTES:   This is an internal routine, not declared in the interface section
  2428. ----------------------------------------------------------------------------
  2429. --}
  2430. procedure FlagUIntOverflow;
  2431. begin
  2432.     raise EIntOverflow.Create('Unsigned integer overflow in RDMath');
  2433. end {FlagUIntOverflow};
  2434.  
  2435.  
  2436. {---------------------------------------------------------------------------
  2437. ---
  2438. PURPOSE:     Multiply two unsigned 32-bit integers, checking for overflow
  2439. DATE:        March 2001
  2440. EXCEPTIONS:  EIntOverflow  if the product will not fit into a LongWord
  2441. NOTES:       1. This is needed in Delphi 5.01, since an attempt to multiply two
  2442.              LongWords results in signed multiplication.
  2443. ----------------------------------------------------------------------------
  2444. --}
  2445. function UMul (const Num1, Num2: LongWord): LongWord;
  2446. asm
  2447.     // Num1 is in eax, Num2 is in edx
  2448.     mul     edx               // product now in edx:eax
  2449.     jc      FlagUIntOverflow  // error on overflow
  2450. end {UMul};
  2451.  
  2452.  
  2453. {---------------------------------------------------------------------------
  2454. ---
  2455. PURPOSE:     Multiply two unsigned 32-bit integers then divide by 2**32 (i.e.
  2456.            return the upper DWORD of the product)
  2457. DATE:        Modified 13 Apr 2001 to use LongWords instead of Integers
  2458. EXCEPTIONS:  None, since the answer always fits into 32 bits
  2459. NOTES:       This is useful in randomizing routines, to scale one integer by
  2460.            the other relative to 32 bits (reduce one integer according to the
  2461.            size of a second integer).
  2462. ----------------------------------------------------------------------------
  2463. --}
  2464. function UMulDiv2p32 (const Num1, Num2: LongWord): LongWord;
  2465. asm
  2466.     // Num1 is in eax, Num2 is in edx
  2467.     mul     edx           // result is in edx:eax
  2468.     mov     eax,edx       // return high dword
  2469. end {UMulDiv2p32};
  2470.  
  2471.  
  2472. {---------------------------------------------------------------------------
  2473. ---
  2474. PURPOSE:     Multiply two unsigned 32-bit integers then divide by another
  2475.            unsigned 32-bit integer.
  2476. DATE:        Created December 1998
  2477.            Modified 13 Apr 2001 to use LongWords instead of Integers
  2478. EXCEPTIONS:  EDivByZero  if the divisor is zero
  2479.            (see Note 1)
  2480. NOTES:       1. The product followed by division will cause an unflagged
  2481.              integer overflow if the answer will not fit into 32 bits. In
  2482.              this case, the returned value is the lower 32-bits of the true
  2483.              answer.  This will never be a problem if the two multipliers
  2484.              are below the divisor.
  2485.            2. The result is truncated toward zero (as in most integer
  2486.              divides).
  2487.            3. This is useful in randomizing routines, to scale one integer by
  2488.              the other relative to a third (reduce one integer according to
  2489.              the relative size of a second integer compared to a third
  2490.              integer).
  2491.            4. The Win32 API has a similar function MulDiv(), but it works on
  2492.              signed integers and rounds the quotient.
  2493. ----------------------------------------------------------------------------
  2494. --}
  2495. function UMulDiv (const Num1, Num2, Divisor: LongWord): LongWord;
  2496. asm
  2497.     // Num1 is in eax, Num2 is in edx, Divisor is in ecx
  2498.     mul     edx           // product now in edx:eax
  2499.     div     ecx           // quotient now in eax, remainder in edx
  2500. end {UMulMod};
  2501.  
  2502.  
  2503. {---------------------------------------------------------------------------
  2504. ---
  2505. PURPOSE:     Multiply two unsigned 32-bit integers then take the modulus by
  2506.            another unsigned 32-bit integer.
  2507. DATE:        Created December 1998
  2508.            Modified 13 Apr 2001 to use LongWords instead of Integers
  2509. EXCEPTIONS:  EDivByZero   if the divisor is zero
  2510.            (See Note 1)
  2511. NOTES:       1. There is never an overflow error, since the answer always fits
  2512.              into 32 bits.
  2513.            2. This is useful in linear congruential generators.
  2514. ----------------------------------------------------------------------------
  2515. --}
  2516. function UMulMod (const Num1, Num2, Modulus: LongWord): LongWord;
  2517. asm
  2518.     // Num1 is in eax, Num2 is in edx, Modulus is in ecx
  2519.     mul     edx           // product now in edx:eax
  2520.     div     ecx           // quotient now in eax, remainder in edx
  2521.     mov     eax,edx       // return the remainder
  2522. end {UMulMod};
  2523. {$ENDIF}
  2524.  
  2525. {--- Special Functions ---}
  2526.  
  2527. function InverseGamma (const X: Extended): Extended;
  2528. var
  2529.     C: array [1..26] of Extended;
  2530.     Z: Extended;
  2531.     XF: Extended;
  2532.     I: Integer;
  2533. begin
  2534.     C [1]  :=  1;
  2535.     C [2]  :=  0.5772156649015329;
  2536.     C [3]  := -0.6558780715202538;
  2537.     C [4]  := -0.0420026350340952;
  2538.     C [5]  :=  0.1665386113822915;
  2539.     C [6]  := -0.0421977345555443;
  2540.     C [7]  := -0.0096219715278770;
  2541.     C [8]  :=  0.0072189432466630;
  2542.     C [9]  := -0.0011651675918591;
  2543.     C [10] := -0.0002152416741149;
  2544.     C [11] :=  0.0001280502823882;
  2545.     C [12] := -0.0000201348547807;
  2546.     C [13] := -0.0000012504934821;
  2547.     C [14] :=  0.0000011330272320;
  2548.     C [15] := -0.0000002056338417;
  2549.     C [16] :=  0.0000000061160950;
  2550.     C [17] :=  0.0000000050020075;
  2551.     C [18] := -0.0000000011812746;
  2552.     C [19] :=  0.0000000001043427;
  2553.     C [20] :=  0.0000000000077823;
  2554.     C [21] := -0.0000000000036968;
  2555.     C [22] :=  0.0000000000005100;
  2556.     C [23] := -0.0000000000000206;
  2557.     C [24] := -0.0000000000000054;
  2558.     C [25] :=  0.0000000000000014;
  2559.     C [26] :=  0.0000000000000001;
  2560.     Result := 0;
  2561.     Z := 1;
  2562.     XF := Frac (X);
  2563.     if XF = 0 then
  2564.         XF := Sgn (X);
  2565.     for I := 1 to 26 do
  2566.     begin
  2567.         Z := Z * XF;
  2568.         Result := Result + C [I] * Z;
  2569.     end;
  2570.     if X > 0 then
  2571.     begin
  2572.         while XF < X do
  2573.         begin
  2574.             Result := Result / XF;
  2575.             XF := XF + 1;
  2576.         end;
  2577.     end
  2578.     else if X < 0 then
  2579.     begin
  2580.         while XF > X do
  2581.         begin
  2582.             XF := XF - 1;
  2583.             Result := XF * Result;
  2584.         end;
  2585.     end
  2586. end;
  2587.  
  2588. function Gamma (const X: Extended): Extended;
  2589. begin
  2590.     Result := InverseGamma (X);
  2591.     if abs (Result) < 1e-4000 then
  2592.         raise EMathError.Create ('Not Defined for given Value')
  2593.     else
  2594.         Result := 1 / Result;
  2595. end;
  2596.  
  2597. { Logarithm to base e of the gamma function.
  2598.  
  2599.   Accurate to about 1.e-14.
  2600.   Programmer: Alan Miller
  2601.  
  2602.   Latest revision of Fortran 77 version - 28 February 1988
  2603. }
  2604. function LnGamma (const X: Extended): Extended;
  2605. const
  2606.     A1 = -4.166666666554424E-02;
  2607.     A2 = 2.430554511376954E-03;
  2608.     A3 = -7.685928044064347E-04;
  2609.     A4 = 5.660478426014386E-04;
  2610. var
  2611.     Temp, Arg, Product: Extended;
  2612.     Reflect: Boolean;
  2613. begin
  2614. //  lngamma is not defined if x = 0 or a negative integer.
  2615.     if FloatIsZero (X) or FloatIsNegative (X) and (Abs (X - Int (X)) < ESBTolerance) then
  2616.         raise EMathError.Create ('Invalid Value');
  2617.  
  2618. // If X < 0, use the reflection formula:
  2619. //        gamma(x) * gamma(1-x) = pi * cosec(pi.x)
  2620.  
  2621.     Reflect := X < 0.0;
  2622.     if Reflect then
  2623.         Arg := 1.0 - X
  2624.     else
  2625.         Arg := X;
  2626.  
  2627. // Increase the argument, if necessary, to make it > 10.
  2628.  
  2629.     Product := 1.0;
  2630.     while (Arg <= 10.0) do
  2631.     begin
  2632.         Product := Product * Arg;
  2633.         Arg := Arg + 1.0;
  2634.     end;
  2635.  
  2636. // Use a polynomial approximation to Stirling's formula.
  2637. // N.B. The real Stirling's formula is used here, not the simpler, but less
  2638. //     accurate formula given by De Moivre in a letter to Stirling, which
  2639. //     is the one usually quoted.
  2640.  
  2641.     Arg := Arg - 0.5;
  2642.     Temp := 1.0 / Sqr (Arg);
  2643.     Result := LnRt2Pi + Arg * (Ln (Arg) - 1.0 +
  2644.         (((A4 * Temp + A3) * Temp + A2) * Temp + A1) * Temp) - Ln (Product);
  2645.  
  2646.     if Reflect then
  2647.     begin
  2648.         Temp := Sin (ESBPi * X);
  2649.         Result := Ln (ESBPi / Temp) - Result;
  2650.     end;
  2651. end;
  2652.  
  2653. function Beta (const X, Y: Extended): Extended;
  2654. var
  2655.     R1, R2: Extended;
  2656. begin
  2657.     R1 := InverseGamma (X);
  2658.     R2 := InverseGamma (Y);
  2659.     if FloatIsZero (R1) or FloatIsZero (R2) then
  2660.         raise EMathError.Create ('Not Defined for given Value')
  2661.     else
  2662.         Result := InverseGamma (X + Y) / (R1 * R2);
  2663. end;
  2664.  
  2665. function IncompleteBeta (X: Extended; P, Q: Extended): Extended;
  2666. { Adapted From Collected Algorithms from CACM
  2667.     Algorithm 179 - Incomplete Beta Function Ratios
  2668.     Oliver G Ludwig
  2669. }
  2670. const
  2671.     Epsilon: Extended = 0.5e-18;
  2672.     MaxIterations = 1000;
  2673. var
  2674.     FinSum, InfSum, Temp, Temp1, Term, Term1, QRecur, Index: Extended;
  2675.     I : Integer;
  2676.     Alter: Boolean;
  2677. begin
  2678.     if (P <= 0) or (Q <= 0) or (X < 0) or (X > 1) then
  2679.         raise EMathError.Create ('Not Defined for given Value')
  2680.     else
  2681.     begin
  2682.         if (X = 0) or (X = 1) then
  2683.             Result := X
  2684.         else
  2685.         begin
  2686.             // Interchange arguments if necessary to get better convergence
  2687.             if X <= 0.5 then
  2688.                 Alter := False
  2689.             else
  2690.             begin
  2691.                 Alter := True;
  2692.                 SwapExt (P, Q);
  2693.                 X := 1 - X;
  2694.             end;
  2695.  
  2696.             // Recurs on the (effective) Q until the Power Series doesn't alternate
  2697.             FinSum := 0;
  2698.             Term := 1;
  2699.             Temp := 1 - X;
  2700.             QRecur := Q;
  2701.             Index := Q;
  2702.             repeat
  2703.                 Index := Index - 1;
  2704.                 if Index <= 0 then
  2705.                     Break;
  2706.                 QRecur := Index;
  2707.                 Term := Term * (QRecur + 1) / (Temp * (P + QRecur));
  2708.                 FinSum := FinSum + Term;
  2709.             until False;
  2710.  
  2711.             // Sums a Power Series for non-integral effective Q and yields unity for integer Q
  2712.             InfSum := 1;
  2713.             Term := 1;
  2714.             for I := 1 to MaxIterations do
  2715.             begin
  2716.                 if Term <= Epsilon then
  2717.                     Break;
  2718.                 Index := I;
  2719.                 Term := Term * X * (Index - QRecur) * (P + Index - 1) /
  2720.                     (Index * (P + Index));
  2721.                 InfSum := InfSum + Term;
  2722.             end;
  2723.  
  2724.             // Evaluates Gammas
  2725.             Temp := Gamma (QRecur);
  2726.             Temp1 := Temp;
  2727.             Term := Gamma (QRecur + P);
  2728.             Term1 := Term;
  2729.             Index := QRecur;
  2730.             repeat
  2731.                 Temp1 := Temp1 * Index;
  2732.                 Term1 := Term1 * (Index + P);
  2733.                 Index := Index + 1;
  2734.             until Index >= Q - 0.5;
  2735.  
  2736.             Temp := XtoY (X, P) * (InfSum * Term / (P * Temp) + FinSum * Term1
  2737.                 * XtoY (1 - X, Q) / (Q * Temp1))/Gamma (P);
  2738.  
  2739.             if Alter then
  2740.                 Result := 1 - Temp
  2741.             else
  2742.                 Result := Temp
  2743.         end;
  2744.     end;
  2745. end;
  2746.  
  2747. {------------------------------------------------------------------------
  2748. PURPOSE:     Calculate the greatest integral power of two that is less
  2749.            than or equal to the parameter
  2750. DATE:        April 2000
  2751. EXCEPTIONS:  EInvalidArgument for argument zero
  2752. ------------------------------------------------------------------------}
  2753. function IGreatestPowerOf2 (const N: LongWord): LongWord;
  2754. begin
  2755.     Result := LongWord(1) shl ILog2 (N);
  2756. end {GreatestPowerOf2};
  2757.  
  2758. end.
  2759.