Sordie.co.uk

libsassy/libSassy.Maths.pas

Raw

{(
 )) libSassy.Maths
((    Mathematical functions
 ))
((  Copyright  Sordie Aranka Solomon-Smith 2015-2017
 ))
((  This work is made available under the terms of the Creative Commons
 )) Attribution-NonCommercial-ShareAlike 3.0 Unported license
((  http://creativecommons.org/licenses/by-nc-sa/3.0/
 )}

unit libSassy.Maths;

interface

{$REGION 'SinCos'}
procedure SinCos(Theta: Extended; var s, c: Extended);
function ArcTan2(x, y: Extended): Extended;
function ArcSin(x: Extended): Extended;
function ArcCos(x: Extended): Extended;
{$ENDREGION}

{$REGION 'Power'}
function Power(Base, Exponent: Extended): Extended;
function IntPower(Base: Extended; Exponent: Integer): Extended;
{$ENDREGION}

{$REGION 'Interpolation'}
function LinearInterpolate(const a, b,       i: Extended): Extended;
function CosineInterpolate(const a, b,       i: Extended): Extended;
function CubicInterpolate (const a, b, c, d, i: Extended): Extended;
{$ENDREGION}

implementation

{$REGION 'SinCos'}
procedure SinCos;
asm
  fld Theta
  fsincos
  fstp tbyte ptr [edx]
  fstp tbyte ptr [eax]
  fwait
end;

function ArcTan2;
asm
  fld x
  fld y
  fpatan
  fwait
end;

function ArcSin;
begin
  Result := ArcTan2(x, Extended(Sqrt((1 + x) * (1 - x))));
end;

function ArcCos;
begin
  Result := ArcTan2(Sqrt((1 + x) * (1 - x)), x);
end;
{$ENDREGION}

{$REGION 'Power'}
function Power;
begin
  if Exponent = 0.0 then
    Result := 1.0
  else if (Base = 0.0) and (Exponent > 0.0) then
    Result := 0.0
  else if (Frac(Exponent) = 0.0) and (Abs(Exponent) <= MaxInt) then
    Result := IntPower(Base, Integer(Trunc(Exponent)))
  else if Base < 0 then
    Result := 0
  else
    Result := Exp(Exponent * Ln(Base));
end;

function IntPower;
var
  Y:     Integer;
  LBase: Extended;
begin
  Y := Abs(Exponent);

  LBase := Base;
  Result := 1.0;

  while Y > 0 do
  begin
    while not Odd(Y) do
    begin
      Y     := Y shr 1;
      LBase := LBase * LBase
    end;

    Dec(Y);
    Result := Result * LBase
  end;

  if Exponent < 0 then
    Result := 1.0 / Result;
end;
{$ENDREGION}

{$REGION 'Interpolation'}
function LinearInterpolate;
begin
  Result := a + ((b - a) * i);
end;

function CosineInterpolate;
begin
  Result := a + ((b - a) * ((1 - cos(i * pi)) * 0.5));
end;

function CubicInterpolate;
  function Pow(const a: Extended; const b: Integer): Extended;
  var
    i:  Integer;
  begin
    Result := 1;
    for i := 1 to b do
      Result := Result * a;
  end;
begin
  Result := (((d - c) - (a - b)) * pow(i, 3)) + (((a - b) - ((d - c) - (a - b))) * pow(i, 2)) + ((c - a) * i) + b;
end;
{$ENDREGION}

end.