Nächstgrößere, nächstkleinere Fließkommazahl

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Ekkehard
Beiträge: 69
Registriert: So 12. Feb 2023, 12:42
OS, Lazarus, FPC: Windows Lazarus 3.6, FPC 3.2.2
CPU-Target: 64-Bit
Wohnort: Hildesheim

Re: Nächstgrößere, nächstkleinere Fließkommazahl

Beitrag von Ekkehard »

Mathias hat geschrieben: Do 5. Sep 2024, 17:34

Code: Alles auswählen

    Pointer(nextafter) := GetProcAddress(HDll, '_nextafter');
Muss da nicht auch folgendes rein ?

Code: Alles auswählen

  nextafter_NAME = {$ifdef linux} 'nextafter' {$else} '_nextafter' {$endif};
...
    Pointer(nextafter) := GetProcAddress(HDll, nextafter_NAME);
Unter der Prämisse, diese ganze Methodik "LoadLibrary" und "GetProcAddess" unter Linux genauso wie unter Windows funktioniert: ja.
Ich kenne mich leider mit DLLs und Linux gar nicht aus.

Ekkehard
Beiträge: 69
Registriert: So 12. Feb 2023, 12:42
OS, Lazarus, FPC: Windows Lazarus 3.6, FPC 3.2.2
CPU-Target: 64-Bit
Wohnort: Hildesheim

Re: Nächstgrößere, nächstkleinere Fließkommazahl

Beitrag von Ekkehard »

Zvoni hat geschrieben: Do 5. Sep 2024, 15:30
UNd funktionierts mit meinem Fund (Benötigt Unit Math)?
Zvoni hat geschrieben: Do 5. Sep 2024, 10:53
af0815 hat geschrieben: Do 5. Sep 2024, 10:33 Wenn die Pascalumsetzung gestestet ist, wäre das nicht ein Featurerequest zumn Einfügen in die Unit Math wert ? Eventuell gleich mit Testcases.
Hab das hier gefunden: https://www.mail-archive.com/fpc-pascal ... 55419.html
Ja, das Zeug funktioniert auf Anhieb, allerdings gefällt mir die Formatierung und Schreibung nicht, deshalb habe ich mir erlaubt, das Ganze etwas hübscher zu schreiben, so dass auch der Compiler nicht meckert etc. pp. An der eigentlichen Funktionalität habe ich natürlich nichts verändert.

Unit "nextfloat.pas" als Anhang.

Mein Testprogramm ist nicht so exportierbar, könnte man aber noch machen, wenn das nötig wäre.
Im Prinzip sieht das so aus, dass ich einige Zufällige Werte um 0.0 herum in einigen Bereichen getestet habe.

Code: Alles auswählen

  for j := 0 to 10000-1 do
  begin
    ds := (Random()-0.5)*10; //1e6,  MaxDouble, 1e-306;
    dd := (Random()-0.5)*10; //1e6,  MaxDouble, 1e-306;
    ddll := umsvcrtdll.nextafter(ds,dd);
    dfpc := unextfloat.NextAfter(ds,dd);
    if ddll <> dfpc then
    begin
      memo1.Lines.Add(Format('Different %d',[j]));
      Exit;
   end;
  end;
  memo1.Lines.Add('No differences found!');
Dateianhänge
unextfloat.pas
(8.83 KiB) 91-mal heruntergeladen

Warf
Beiträge: 2158
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Nächstgrößere, nächstkleinere Fließkommazahl

Beitrag von Warf »

Ekkehard hat geschrieben: Do 5. Sep 2024, 15:26 Die Idee scheint mir schon richtig, aber diese Funktionen versagen fast schon beim ersten Test.
Ruft man
floatNext(-1.0);
auf, so ist das Ergebnis kleiner (negativer) als -1.0 geworden und nicht größer also näher an -0.99.
predNext(-1.0) liefert in diesem Fall dann das richtige Ergebnis.
Da stimmt was mit der Verarbeitung der Vorzeichen nicht.

Anpasssen an Double funktioniert auch nicht wie vermutet, weil da die Maske 11 Bits sein müssen und nicht 7 ((1 shl ValueBits) - 1) schief geht, es muss $0EFF raus kommen.
Gruß Ekkehard

Gruß Ekkehard
Das mit negativen Zahlen funktioniert so wie gewollt, es inkrementiert immer weg von 0 und dekrementiert immer Richtung null (hab ich in einem der vorigen posts geschrieben), das ist schon so gewollt. Ich geb zu die Namen der Funktionen könnten besser sein.

Der Grund ist relativ einfach, aus Effizienzgründen wollte ich if-then-else vermeiden (wie du sehen kannst ist die Funktion rein arithmetische ohne kontrollfluss operatoren). Ums für so Fälle benutzbar zu machen muss man halt noch code drum herum bauen.

Und mit Double kann ich Grade nicht testen da ich am Handy bin, aber eigentlich müsste es funktionieren, denn es ist egal wie viele Bits der Exponent und die mantisse haben, zusammen haben sie immer ein Bit weniger als die Gesamtlänge. Die Funktion Splittes lediglich zwischen sign bit und rest.

Ekkehard
Beiträge: 69
Registriert: So 12. Feb 2023, 12:42
OS, Lazarus, FPC: Windows Lazarus 3.6, FPC 3.2.2
CPU-Target: 64-Bit
Wohnort: Hildesheim

Re: Nächstgrößere, nächstkleinere Fließkommazahl

Beitrag von Ekkehard »

Warf hat geschrieben: Do 5. Sep 2024, 19:00 Das mit negativen Zahlen funktioniert so wie gewollt, es inkrementiert immer weg von 0 und dekrementiert immer Richtung null (hab ich in einem der vorigen posts geschrieben), das ist schon so gewollt. Ich geb zu die Namen der Funktionen könnten besser sein.

Der Grund ist relativ einfach, aus Effizienzgründen wollte ich if-then-else vermeiden (wie du sehen kannst ist die Funktion rein arithmetische ohne kontrollfluss operatoren). Ums für so Fälle benutzbar zu machen muss man halt noch code drum herum bauen.

Und mit Double kann ich Grade nicht testen da ich am Handy bin, aber eigentlich müsste es funktionieren, denn es ist egal wie viele Bits der Exponent und die mantisse haben, zusammen haben sie immer ein Bit weniger als die Gesamtlänge. Die Funktion Splittes lediglich zwischen sign bit und rest.
Angesichts des Umstandes, dass das andere Zeug läuft, stelle ich meine Bemühungen an der Stelle derweil ein, insbesondere, weil es mir nicht so sehr auf die Effizienz ankommt. Vielleicht kann man diesen Ansatz zur Steigerung der Effizienz in die o.a. Unit "nextfloat" integrieren. Das dürfte deshalb relativ elegant gehen, weil der ursprüngliche Autor auch den Ansatz verfolgte im Kern "Hin zur Null" und "Weg von der Null" zu implementieren und das andere als Klammer außenrum.

Gruß Ekkehard

Ekkehard
Beiträge: 69
Registriert: So 12. Feb 2023, 12:42
OS, Lazarus, FPC: Windows Lazarus 3.6, FPC 3.2.2
CPU-Target: 64-Bit
Wohnort: Hildesheim

Re: Nächstgrößere, nächstkleinere Fließkommazahl

Beitrag von Ekkehard »

Ekkehard hat geschrieben: Do 5. Sep 2024, 18:51
Unit "nextfloat.pas" als Anhang.
Ich habe noch zwei drei Kleinigekeiten gebügelt, deshalb eine neue Version (keinerlei Änderung der Funktionalität!).
Dateianhänge
unextfloat.pas
(8.86 KiB) 107-mal heruntergeladen

Ekkehard
Beiträge: 69
Registriert: So 12. Feb 2023, 12:42
OS, Lazarus, FPC: Windows Lazarus 3.6, FPC 3.2.2
CPU-Target: 64-Bit
Wohnort: Hildesheim

Re: Nächstgrößere, nächstkleinere Fließkommazahl

Beitrag von Ekkehard »

Ekkehard hat geschrieben: Do 5. Sep 2024, 20:36
Ekkehard hat geschrieben: Do 5. Sep 2024, 18:51
Unit "nextfloat.pas" als Anhang.
Ich dann doch einen Fehler gefunden :-/
Ich hatte übersehen, dass die fehlerhafte (weil zu große) Variante von MinDouble aus der Unit Math verwendet wurde.
Und deshalb ein Update.
Dateianhänge
unextfloat.pas
(9.09 KiB) 132-mal heruntergeladen
Zuletzt geändert von Ekkehard am Fr 6. Sep 2024, 12:59, insgesamt 1-mal geändert.

Ekkehard
Beiträge: 69
Registriert: So 12. Feb 2023, 12:42
OS, Lazarus, FPC: Windows Lazarus 3.6, FPC 3.2.2
CPU-Target: 64-Bit
Wohnort: Hildesheim

Re: Nächstgrößere, nächstkleinere Fließkommazahl

Beitrag von Ekkehard »

Und hier noch ein Testprogramm für alles (unter Windows, ggf auch unter Linux).
Gruß Ekkehard
Dateianhänge
NextFloatTest.zip
(143.9 KiB) 136-mal heruntergeladen

Ekkehard
Beiträge: 69
Registriert: So 12. Feb 2023, 12:42
OS, Lazarus, FPC: Windows Lazarus 3.6, FPC 3.2.2
CPU-Target: 64-Bit
Wohnort: Hildesheim

Re: Nächstgrößere, nächstkleinere Fließkommazahl

Beitrag von Ekkehard »

Ich habe jetzt den Test auch auf die Single-Versionen der unit ausgeweitet und bin auf einen seltsamen Fehler gestoßen.

Ich vermute es handelt sich tatsächlich um einen Fehler im Compiler.

Und zwar schlagen Vergleiche mittels "=" auf die Konstante MaxSingle in der Unit Math fehl, weil der Compiler MaxSingle vor dem Vergleich in ein Double umwandelt und dann den Vergleich ausführt.
Darauf gekommen bin ich, weil die überladenen Funktion mit dem Parameter-Satz Double aufgerufen wird, wenn MaxSingle als direkter Parameter verwendet wird.
Man muss also immer MaxSingle vor der Benutzung auf einen Single casten
statt MyFunc(MaxSingle) also immer MyFunc(Single(MaxSingle));

Code: Alles auswählen

var
  singlevalue : Single;
begin
  singlevalue := MaxSingle;
  equal := (singlevalue = MaxSingle);
  // equal bekommt den Wert False zugewiesen
  equal := (singlevalue = Single(MaxSingle));
  // equal bekommt den Wert True zugewiesen
end;
Ich habe die Unit unextfloat.pas angepasst (dabei einen unnötigen if-Zweig entfernt) und das ganze Testprogramm entsprechend erweitert und angepasst.
ZIP mit allem anbei.

Gruß Ekkehard
Dateianhänge
NextFloatTest.zip
(145.07 KiB) 111-mal heruntergeladen

Antworten