Wie gesagt, die Gleitkomma-Arithmetik ist exakt, genau so exakt wie Integer-Arithmetik.
Was sollte denn die tan(90°) (Eingabe als Radian, natürlich Uwe) deiner Meinung nach zurückgeben ?
Der richtige Wert wäre vielleicht MAX_SINGLE als größtmögliche Näherung an Infinity ?
Obwohl ich bei tan(90°) nicht meine das es überhaupt + oder - Infinity ist, sondern einfach eine undefinierte Polstelle
(Kann mich auch irren. bin jetzt kein Zahlentheoretiker).
Jedenfalls liefert tan(90°) bei mir irgendwas mit -235343.. zurück, also eine konkrete Zahl die unter dem möglichen Max_Single liegt und relativ "zufällig" ist.
Du hast es immer noch nicht ganz verstanden glaube ich. Das hier:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
s: Single;
d: Double;
e: Extended;
begin
s := DegToRad(90);
d := DegToRad(90);
e := DegToRad(90);
Edit1.Text := FloatToStrF(s, ffFixed, 30, 30);
Edit2.Text := FloatToStrF(d, ffFixed, 30, 30);
Edit3.Text := FloatToStrF(e, ffFixed, 30, 30);
end;
Das liefert für die drei Variablen:
s = 1,570796370506286620
d = 1,570796326794896560
e = 1,570796326794896620
pi/2 wäre nach
diesem Rechner auf 50 Stellen genau: 1.570796326794896619231321691639751442098584699687 6
Die Differenz von dieser
Näherung zu pi/2 ist
für s: -0.000000043711390000768678308360248557901415300312 4471
für d: 0.000000000000000059231321691639751442098584699687 553
für e: -0.000000000000000000768678308360248557901415300312 4471
Derselbe Rechner liefert für
tan(s) = -22877332.42942889836981039204072541441251573432
tan(d) = 16882959411340397.91436507298177193134
tan(e) = -1300934329906107203.0757511956816777
(Auch jeweils auf 50 Stellen genau, etwas was eine CPU von Hause aus nicht kann.)
Die Funktion Tan() ist in Delphi (2007) so realisiert:
Delphi-Quellcode:
function Tan(
const X: Extended): Extended;
{ Tan := Sin(X) / Cos(X) }
asm
FLD X
FPTAN
FSTP ST(0)
{ FPTAN pushes 1.0 after result }
FWAIT
end;
Es wird, wie zu erwarten ist, einfach die tan() Funktion der CPU (bzw. FPU) genutzt, so wie es auch sein sollte für eine Basisfunktionalität. Und hier wird eben mit binären Gleitkommazahlen und Radian gearbeitet, so dass du
niemals auch nur die CHANCE hättest tand(90) mit einem 100%ig exakt richtigen Parameter aufzurufen. Und für die
zwingend gerundeten Parameter
stimmt das Ergebnis das du siehst. Es wäre
falsch hier NaN oder +/-Inf zurückzugeben.
Das ist anders für DEINEN Anwendungsfall, in dem du
explizit Funktionen in Grad nutzen willst. Das ist aber ein Sonderwunsch, und NICHT Aufgabe eines Compilers bzw. des Basisumfangs einer Entwicklungsumgebung. Im Gegenteil: Ich wäre ziemlich sauer wenn Emba so ein Monster für ein popeliges tan() als
Basis hätte wie weiter oben gezeigt, wenn doch die CPU selbst schon eine solche Funktion bietet die für 99,999% aller Echt-Welt-Fälle Werte liefert die den üblichen Ansprüchen genügen. Wer besondere Anforderungen hat, nutzt eben besondere Libs, die entsprechende Fälle anders behandeln; meist auf Kosten der Performance.
Rechnen mit Floats ist
immer ungenau, nicht nur bei Trigonometrie. Wenn dich das hier schon stört, müsstest du eigentlich schon weit eher pochende Schläfen bekommen: Es ist nämlich schon manchmal nicht möglich ein exakt eingegebenes Literal in ein Float zu packen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
s: Single;
begin
s := 0.01;
Edit1.Text := FloatToStrF(s, ffFixed, 30, 30);
end;
Ergebnis: 0,009999999776482582
Hier müsstest du eigentlich schon aufgegeben haben. Aber das ist
normal. Das ist überall so bei aktuellen üblichen Computern, und das war es auch schon Jahrzehnte lang.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)