Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi FMod "streikt" (https://www.delphipraxis.net/193137-fmod-streikt.html)

Johann Steiner 25. Jun 2017 13:00

Delphi-Version: 10 Berlin

FMod "streikt"
 
Liebe Delphianer,


ich möchte mit der Funktion FMod (System.Math) eine ca 150-stellige Zahl zerlegen.
Leider steigt die Funktion bei Zahlenwerten um ca x^20 aus mit der Meldung "Ungültige Gleitkommaoperation".
Laut Hilfe sollte die Funktion Extended-Bereiche beherrschen!

Was kann ich machen, was mache ich falsch?

PS: Delphi-Version: DX 10.2 Starter Edition

himitsu 25. Jun 2017 13:51

AW: FMod "streikt"
 
Extended war nie für den produktiven Einsatz gedacht, sondern nur zur FPU-internen Verwendung.
Ab Windows 64 Bit gibt es diesen Typ auch nicht mehr "nativ" im Delphi.

Und Extended hat auch nur 19-20 "signifikante" Dezimalstellen ... mehr ist einfach nicht möglich und alles außerhalb dieser Stellen ist "undefiniert".

12345678901234567890xxxxxxxxxxxxxxxxxx,xxxxxxxx
123456789012,34567890xxxxxxxxxxxxxxxxxxxxxxxxxx
0,00000000000012345678901234567890xxxxxxxxxxx


Einzige Lösung
* String
* BCD
* BigInt und Co.

gammatester 25. Jun 2017 14:24

AW: FMod "streikt"
 
fmod crasht auch bei double. Ich vermute, daß EMBA intern floor oder trunc verwendet, und die crashen halt wenn der Integerbereich übertreten wird (habe auch Starter ohne Quellcode).

Mit int hat man solche Probleme nicht (ob solche Rechnungen sinnvoll sind, ist eine andere Frage)
Delphi-Quellcode:
var
  x,y,z: double;
begin
  try
  x := 1.23e150;
  y := 2e20;
  z := int(x/y);
  z := x-z*y;
  writeln(z);
  z := fmod(x,y);
  writeln(z);
    { TODO -oUser -cConsole Main : Insert code here }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

mensch72 25. Jun 2017 14:35

AW: FMod "streikt"
 
150 Stellen... das über Fließkomma zu machen ist der falsche Weg, selbst wenn es ginge.

da gibt es Leute die haben genau dafür was passendes gemacht, und bieten es ganz unten auf der Seite sogar recht aktuell zum Download an:)
http://www.delphiforfun.org/Programs...g_integers.htm

himitsu 25. Jun 2017 14:46

AW: FMod "streikt"
 
Zitat:

Delphi-Quellcode:
function FMod(const ANumerator, ADenominator: Extended): Extended;
begin
  Result := ANumerator - Trunc(ANumerator / ADenominator) * ADenominator;
end;

:stupid:

gammatester 25. Jun 2017 14:50

AW: FMod "streikt"
 
Zitat:

Zitat von mensch72 (Beitrag 1375311)
150 Stellen... das über Fließkomma zu machen ist der falsche Weg, selbst wenn es ginge.

Das ist ja nicht das Problem. fmod hat nicht zu crashen, das ist mit Vorbehalt ein Delphi-Bug, da EMBA zumindest in der Hilfe keine Beschränkung erwähnt (ein Crash wäre OK, wenn der Quotient einen Overflow ergäbe).

Wenn man große Integer-Zahlen bearbeitet will, kann man mein http://www.wolfgang-ehrhardt.de/misc_de.html#mparith benutzen.

Edit: Dank an himitsu, der meine Vermutung bestätigt.

himitsu 25. Jun 2017 15:59

AW: FMod "streikt"
 
Zitat:

Zitat von gammatester (Beitrag 1375309)
ob solche Rechnungen sinnvoll sind, ist eine andere Frage

Ich kann dir die Lösung sogar aus dem Kopf nennen, wenn ich alle "ungültigen" Dezimalstellen wegrunde.
1.23e150 fmod 2e20 = 0

Johann Steiner 25. Jun 2017 22:11

AW: FMod "streikt"
 
Herzlichen Dank an alle!
Habt mir sehr geholfen.

sko1 26. Jun 2017 06:33

AW: FMod "streikt"
 
Nebenfrage:

Wozu benötigt man eine 150 stellige Zahl?

Ciao
Stefan

Jasocul 26. Jun 2017 06:38

AW: FMod "streikt"
 
Zitat:

Zitat von sko1 (Beitrag 1375321)
Wozu benötigt man eine 150 stellige Zahl?

Zum Beispiel bei der Primzahlberechnung
Gibt sicher noch mehr Beispiele. Was in diesem Thread der Grund ist, weiß ich allerdings auch nicht. :wink:

Rollo62 26. Jun 2017 19:06

AW: FMod "streikt"
 
Ich hätte dazu auch noch ne Frage:
Wie bekommt man denn eine 150-stellige Zahl überhaupt hin ?
Extended sollte doch sofort auf 18-20 Stellen kürzen, oder bleibt 1.2E150 etwa so bestehen ?

Delphi-Quellcode:
    LExt := 1.2E-150;
    LExt := LExt + 0.1E-150; // Das geht tatsächlich
    LExt := Sin(LExt);       // Das aber wohl nicht

    LExt := 1.2E-150;
    LExt := LExt + 0.1E-149; // Das geht tatsächlich

    LExt := 1.2E150;
    LExt := LExt + 0.1E150;  // Das geht tatsächlich
    LExt := Sin(LExt);       // Das wohl auch nicht
Ich benutze solche Extremen normalweise nicht, bin aber auch etwas schockiert das es nur "teilweise" funktioniert.
Anscheinend kann man mit Mantisse/Exponent rechnen, aber mit keine Funktion.
Da hoffe ich mal das ich sowas nie brauchen werde.

Rollo

himitsu 26. Jun 2017 20:55

AW: FMod "streikt"
 
Zitat:

Zitat von Rollo62 (Beitrag 1375402)
Ich hätte dazu auch noch ne Frage:
Wie bekommt man denn eine 150-stellige Zahl überhaupt hin ?
Extended sollte doch sofort auf 18-20 Stellen kürzen, oder bleibt 1.2E150 etwa so bestehen ?

Siehe Post #2.

Das Stichwort heißt "signifikante Dezimalstellen"

Eine Fließkommazahl besteht aus dem Vorzeichen (+ oder -), der Mantisse und dem Exponent.
Die Mantisse ist der Teil, in welchem die 18-20 "signifikanten" Dezimalstellen stecken und mit dem Exponent kann man ihn hin und her schieben, also bei Extended um fast 5000 Dezimalstellen vor oder hinter das Komma. (bei Double etwa 300 Dezimalstellen)

3,4xxxxxxxxxxxxxxxxx * 10^-4932 bis 1,1xxxxxxxxxxxxxxxxxx * 10^4932
3,4xxxxxxxxxxxxxxxxx / 10^4932 bis 1,1xxxxxxxxxxxxxxxxxx * 10^4932
das im Positiven und nochmal im degativen Bereich, zuzüglich der 0 und den Sonterwerten NAN, Infinity und NegInfinity.

https://www.h-schmidt.net/FloatConverter/IEEE754de.html
https://de.wikipedia.org/wiki/Mantisse

Sherlock 27. Jun 2017 07:59

AW: FMod "streikt"
 
Zur Frage wie man 150 Stellen überhaupt hinbekommt: Man muss sich mit eigenen Typen behelfen. Hier mal ein Beispiel:
http://www.delphiforfun.org/Programs...g_integers.htm

Sherlock

gammatester 27. Jun 2017 09:04

AW: FMod "streikt"
 
Zitat:

Zitat von Rollo62 (Beitrag 1375402)
Ich hätte dazu auch noch ne Frage:
Wie bekommt man denn eine 150-stellige Zahl überhaupt hin ?
Extended sollte doch sofort auf 18-20 Stellen kürzen, oder bleibt 1.2E150 etwa so bestehen ?

Delphi-Quellcode:
    LExt := 1.2E150;
    LExt := LExt + 0.1E150;  // Das geht tatsächlich
    LExt := Sin(LExt);       // Das wohl auch nicht
Ich benutze solche Extremen normalweise nicht, bin aber auch etwas schockiert das es nur "teilweise" funktioniert.

Ich glaube Du solltest Dir erst einmal klar werden, was Du unter "Stellen" verstehst. Bei Ganzzahl-Werten sind die "Stellen" tatsächlich so etwas wie die Anzahl der einzelnen (Dezimal-)Ziffern.

Bei Fließkomma-Zahlen (double) hat man sowas wie m*10^e, wobei im wesentlichen m eine Ganzzahl zwischen 0 und ca 10^16 ist. Hier hat ein double also ca 16 (signifikante "Stellen").

Bei Fließkomma-Rechnungen wird immer auf diese 16 Stellen gerundet und das hat manchmal komische Konsequenzen, zB wird 2E16 + 1 = 20000000000000000 + 1 = 20000000000000001 zu 20000000000000000 gerundet, d.h. Du kannst beliebig oft 1 zu 2E16 addieren ohne das sich der Double-Wert ändert.

Daß sin(1e150) nicht funktioniert, ist ein Delphi-Bug (EMBA wird sagen 'Feature').

Rollo62 27. Jun 2017 16:08

AW: FMod "streikt"
 
Ja ich bin von signifikanten Stellen ausgegangen. Das sin (e150) nicht funktioniert finde ich schon erschreckend. Ich hatte mit dem erstbesten online js Rechner getestet und der konnte etwas sinnvolles zurückgeben.

Das heisst für mich erstmal Achtung bei fliesskomma Rechnungen.
Mit Rundungsfehlern hätte ich gerechnet aber solche logikfehler eher nicht.

Johann Steiner 1. Jul 2017 00:03

AW: FMod "streikt"
 
Hallo Leute,
die Ursache für die Entstehung des Problems war das März-Preisrätsel 2017 in Bild der Wissenschaft.
Dabei hat mich nicht die "Lösung des Problems" interessiert, sondern wie das Endergebnis ausschaut und ob bei jeder diversen Losziehung das gleiche Ergebnis herauskommt.
Die Berechnung war kein Problem, Double genügt, aber das gesamte Ergebnis als String darzustellen war mir unmöglich.
Als FMode bei e^21 ausstieg war ich schon sehr erstaunt (nicht einmal Single wird überschritten!), zumal in der Hilfe doch die Funktion mit Extended-Werten umgehen sollte können.
So wollte ich das machen:
function ExtToString(source:Extended): string;
const
CharDigits = '0123456789';
var Rest:integer;
begin
Result := '';
repeat
Rest:= Round(FMod(Source, 10))+1;
Result := CharDigits[Rest] + Result;
ASource := Int(Source / 10);
until (Source = 0);
end;
Nach euren Hinweisen habe ich die Unit UBigIntsV5 von Gary Darby verwendet und es klappt hervorragend.

Nochmals herzlichen Dank an alle!


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:15 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz