Einzelnen Beitrag anzeigen

gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#25

AW: tan() von Single, Double, etc.

  Alt 21. Nov 2017, 09:49
Richtig, aber so sollte eine tand(x) Funktion mit Argumenten in ° ja auch nicht programmiert werden
Da zum Delphi-Sprachumfang aber nun mal keine tand-Funktion gehört (Delphi 5 kannte noch nicht einmal tan), kann man sich ja bei Bedarf was Passendes selbst programmieren. Mach doch mal einen Vorschlag so wie du es dir vorstellst.
Hier eine vereinfachte Implementation meiner DAMath-Funktion komplett mit Test-Programm
Delphi-Quellcode:
{Test/dev program for tand  (c) W.Ehrhardt 2017}
program t_tand;

{$apptype console}

uses
  math;


{Vereinfachte Implementation einer tand-Funktion, d.h. Tangens mit }
{Argument in Grad. Achtung: nur bis ca 10^13 = 2^53/180 genau, weil}
{ich nicht noch mehr DAMath-Funktioen einbauen wollte. Compilierbar}
{ab Delphi 6}


{---------------------------------------------------------------------------}
function floord(x: double): double;
  {-Return the largest integer <= x}
var
  t: double;
begin
  t := int(x);
  if (x>=0.0) or (x=t) then floord := t
  else floord := t - 1.0;
end;


{---------------------------------------------------------------------------}
procedure trig_deg(x: double; var y,z: double; var n: integer; var m45: boolean);
  {-Reduce x in degrees mod 90; y=x mod 90, |y|<45. z=x/45, m45 if x is multiple of 45}
const
  c45: single = 45.0;
begin
  {Basic internal reduction routine mod 90. Use Cody/Waite logic, but no}
  {pseudo-multiprecision because 45.0 has only 6 non-zero mantissa bits.}
  if x=0.0 then begin
    y := 0.0;
    z := 0.0;
    n := 0;
    m45 := true;
  end
  else begin
    z := x/c45;
    m45 := (frac(z)=0.0) and (frac(x)=0.0);
    y := floord(z);
    n := trunc(y - 16.0*floord(y/16.0));
    if odd(n) then begin
      inc(n);
      y := y + 1.0;
    end;
    n := (n shr 1) and 7;
    y := x - y*c45;
  end;
end;


{---------------------------------------------------------------------------}
function tand(x: double): double;
  {-Return tan(x), x in degrees}
var
  y,z: double;
  n : integer;
  m45: boolean;
begin
  trig_deg(x,y,z,n,m45);
  if m45 then begin
    z := abs(z);
    y := sign(x);
    case round(4.0*frac(0.25*z)) of
        0: tand := 0.0;
        1: tand := y;
        2: tand := Infinity;
      else tand := -y;
    end;
  end
  else begin
    z := DegToRad(y);
    if odd(n) then tand := -cot(z)
    else tand := tan(z);
  end;
end;

var
  d: integer;
begin
  d := 0;
  while d<=360 do begin
    writeln(d:5, tand(d):25:16);
    d := d + 15;
  end;
end.
Die Ausgabe ist dann
Code:
    0       0.0000000000000000
   15       0.2679491924311228
   30       0.5773502691896258
   45       1.0000000000000000
   60       1.7320508075688770
   75       3.7320508075688768
   90                     +Inf
  105      -3.7320508075688768
  120      -1.7320508075688770
  135      -1.0000000000000000
  150      -0.5773502691896258
  165      -0.2679491924311228
  180       0.0000000000000000
  195       0.2679491924311228
  210       0.5773502691896258
  225       1.0000000000000000
  240       1.7320508075688770
  255       3.7320508075688768
  270                     +Inf
  285      -3.7320508075688768
  300      -1.7320508075688770
  315      -1.0000000000000000
  330      -0.5773502691896258
  345      -0.2679491924311228
  360       0.0000000000000000
Im getesteten Bereich -10^10 .. 10^10 ist die Genauigkeit ist die gleiche wie bei DAMath
Code:
Test DAMath V0.95 with MP_Arith V1.37.01 (31/32 bit)  (c) 2013-2017 W.Ehrhardt
Karatsuba cutoffs: mul/sqr = 16/32
Toom-3, BZ cutoffs: mul/sqr = 32/64, div = 32
Current mp_float default bit precision = 160, decimal precision = 48.2
Machine eps for double = 2.22044604925E-0016

-----------------------------------------------------------------
Test of DAMath.tand
at 10000 random values in [-10000000000.0000000000 .. 10000000000.0000000000]
RMS = 0.38, max rel = 1.25 eps at
 x(dbl) = -4.52875830026280448E+0009 = $C1F0DEF5E1C43473
 y(dbl) = -1.75054511612172736E+0000 = $BFFC023B987EA53D
 y(mpf) = -1.75054511612172687511491287528577674916550040814


-----------------------------------------------------------------
Test of tand (Delphi Praxis)
at 10000 random values in [-10000000000.0000000000 .. 10000000000.0000000000]
RMS = 0.38, max rel = 1.25 eps at
 x(dbl) = -4.52875830026280448E+0009 = $C1F0DEF5E1C43473
 y(dbl) = -1.75054511612172736E+0000 = $BFFC023B987EA53D
 y(mpf) = -1.75054511612172687511491287528577674916550040814

Geändert von gammatester (21. Nov 2017 um 10:20 Uhr) Grund: Minus bei cot
  Mit Zitat antworten Zitat