Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Rundungs problem? (https://www.delphipraxis.net/192923-rundungs-problem.html)

EWeiss 1. Jun 2017 17:18


Rundungs problem?
 
Kann diese Funktion ein Rundungs Problem verursachen?

Delphi-Quellcode:
        for y := 0 to (imgH - 1) do
        begin
          for x := 0 to (imgW - 1) do
          begin
            if pBits.rgbReserved > 0 then
            begin
              AlphaCoef := (255 shl 8) div pBits.rgbReserved;
              pBits.rgbBlue := ((pBits.rgbBlue * AlphaCoef) shr 8);
              pBits.rgbGreen := ((pBits.rgbGreen * AlphaCoef) shr 8);
              pBits.rgbRed := ((pBits.rgbRed * AlphaCoef) shr 8);
            end;
            inc(pBits);
          end;
        end;
wenn ja nehme ich besser

Delphi-Quellcode:
        for y := 0 to (imgH - 1) do
        begin
          for x := 0 to (imgW - 1) do
          begin
            if pBits.rgbReserved > 0 then
            begin
              AlphaCoef := (255 shl 16) div pBits.rgbReserved;
              pBits.rgbBlue := ((pBits.rgbBlue * AlphaCoef) shr 16);
              pBits.rgbGreen := ((pBits.rgbGreen * AlphaCoef) shr 16);
              pBits.rgbRed := ((pBits.rgbRed * AlphaCoef) shr 16);
            end;
            inc(pBits);
          end;
        end;
Ich möchte nur eine Bestätigung das es so ist... Danke.

vorher hatte ich es so.. was aber bedingt durch single(float) um ein 4faches langsamer ist.
bitmap: 4096x4096
elapsed: 2763 bei Verwendung von single.
elapsed: 627 und ULong.

Delphi-Quellcode:
        for IntI := (bm.bmWidth * bm.bmHeight) downto 1 do
        begin
          if pBits.rgbReserved > 0 then
          begin
            AlphaCoef := (pBits.rgbReserved / 255);
            pBits.rgbBlue := round(pBits.rgbBlue / AlphaCoef);
            pBits.rgbGreen := round(pBits.rgbGreen / AlphaCoef);
            pBits.rgbRed := round(pBits.rgbRed / AlphaCoef);
          end;
          Inc(pBits);
        end;
gruss

himitsu 1. Jun 2017 17:39

AW: Rundungs problem?
 
je mehr, um so größer rgbReserved ist, bei beiden Versionen, aber kleiner, bei großem Multiplikator, also ja ... die 2.

Aber warum das "gerundete" Zwischenergebnis und nicht gleich direkt gerechnet?
Delphi-Quellcode:
pBits.rgbBlue := (pBits.rgbBlue * 255) div pBits.rgbReserved;




Wenn es schnell sein soll dan kann man die 3 Werte auch zusammen in einem MMX-Register verrechnen lassen.
Und pssst
Delphi-Quellcode:
for allesineinerschleife := 0 to imgH * imgW - 1 do
// oder
for allesineinerschleife := imgH * imgW - 1 downto 0 do // spart noch die interne Ende-Variable, da Ende immer 0

EWeiss 1. Jun 2017 17:41

AW: Rundungs problem?
 
Zitat:

je mehr, um so größer rgbReserved ist, bei beiden Versionen, aber kleiner, bei großem Multiplikator, also ja ... die 2.
Wenn ich dich richtig verstehe die 2. Version mit Shift 16 verwenden.
Die shift 8 könnte also ein Rundungs Problem generieren?

Zitat:

Aber warum das "gerundete" Zwischenergebnis und nicht gleich direkt gerechnet?
auf was beziehst du das bei welchen der 3 Varianten. ?

Danke.

gruss

himitsu 1. Jun 2017 17:49

AW: Rundungs problem?
 
AlphaCoef ist ein gerundetes Zwischenergebnis.
Bei 16 ist das natürlich größer und somit die Rundung geringer.
Aber die Rundung ist dennoch bei 8 und 16 drin, nur eben nicht gleich groß.


Delphi-Quellcode:
pBits.rgbBlue := (pBits.rgbBlue * 255) div pBits.rgbReserved;
=
Delphi-Quellcode:
pBits.rgbBlue := MulDiv(pBits.rgbBlue, 255, pBits.rgbReserved);

aber da deine Werte so klein sind, dass es keinen Überlauf gibt, wäre MulDiv egal (unnötig).

EWeiss 1. Jun 2017 17:58

AW: Rundungs problem?
 
Zitat:

Zitat von himitsu (Beitrag 1373259)
AlphaCoef ist ein gerundetes Zwischenergebnis.
Bei 16 ist das natürlich größer und somit die Rundung geringer.
Aber die Rundung ist dennoch bei 8 und 16 drin, nur eben nicht gleich groß.

Ich habe da ein Beispiel in C von einem Forum wo ich gerade arbeite. (englisch nicht so mein Ding)

Da wird mir gesagt! Das rundungs Probleme auftreten auf der Basis dieser Berechnung.

Zitat:

it will be on some values...
for example alpha=250, color=251... then instead of 0 you will get 255,
same with 251:252, 252:253, 253:254, 254:255, ...
if use shift by 16, then there is no this problem
Shift 16 soll das Problem beheben mag ja in C++ zutreffend sein aber unter Delphi ?
Auf Grund dieser Berechnung.

Code:
      int err = 0;
      for (ULONG a = 0; a < 256; a++)
      {
         float rAlphaCoef = (float)((float)a / 255.0f);
         ULONG uAlphaCoef = a ? ((255 << 8) / a) : 0;

         for (ULONG c = 0; c < 256; c++)
         {
            BYTE n = (BYTE)(int)((float)c / rAlphaCoef);
            BYTE m = (BYTE)(((ULONG)c * uAlphaCoef) >> 8);
            if (n != m && abs(n - m) > 1)
               wprintf(L"error: a: %03d; c: %03d [n: %05d, m: %05d] %i\n", a, c, n, m, ++err);
         }
      }
Ich bin da jetzt etwas unsicher da ich ihm gesagt habe das ich mit Shift 8 eigentlich keine Sichtbaren unterschiede sehe da mein Icon die Transparenz hat die es haben soll.
Deshalb der Post. ;)

gruss

Michael II 1. Jun 2017 18:55

AW: Rundungs problem?
 
Hallo A.Weiss

deine Funktion "Berechne Farbwert'" hängt ja von 2 Parametern Alpha und Farbwert ab.

Wenn die Werte von Alpha und Farbwert in [0..255] liegen, dann schreib doch rasch eine Routine

for Alpha := 0 to 255 do
for FarbWert := 0 to 255 do...

und berechne Farbwert' einerseits nach deiner alten "float basierten Version" und andererseits nach deinen beiden neuen "int Versionen" und vergleiche die Resultate.

Dann weisst du ganz genau was Sache ist.

EWeiss 1. Jun 2017 19:02

AW: Rundungs problem?
 
Zitat:

Zitat von Michael II (Beitrag 1373261)
Hallo A.Weiss

deine Funktion "Berechne Farbwert'" hängt ja von 2 Parametern Alpha und Farbwert ab.

Wenn die Werte von Alpha und Farbwert in [0..255] liegen, dann schreib doch rasch eine Routine

for Alpha := 0 to 255 do
for FarbWert := 0 to 255 do...

und berechne Farbwert' einerseits nach deiner alten "float basierten Version" und andererseits nach deinen beiden neuen "int Versionen" und vergleiche die Resultate.

Dann weisst du ganz genau was Sache ist.

Danke das habe ich ja gemacht.

bitmap: 4096x4096
elapsed: 2763 bei Verwendung von single.
elapsed: 627 und ULong.

es geht mir darum ob nun eine Rundungsfehler auftreten kann oder nicht..
Ich konnte keinen ausmachen aber es wird mir so im C++ Forum berichtet ;)
Nun wem oder was soll man nun glauben.

Also unter C++ soll er auftreten und in Delphi nach meinen Tests aber nicht.
Was stimmt denn nun.

gruss

himitsu 1. Jun 2017 19:06

AW: Rundungs problem?
 
Och, so viel ist das auch nicht, da kann man docg problemlos alle Varianten vorberechnen und dann nur noch aus der Liste picken.
Delphi-Quellcode:
type
  PColorArray = ^TColorArray;
  TColorArray = array[0..255] of Integer;
  TAlphaArray = array[0..255] of TColorArray;
var
  AlphaArray: TAlphaArray;
  ColorArray: PColorArray;

for IntI := (bm.bmWidth * bm.bmHeight) - 1 downto 0 do begin
  if pBits.rgbReserved <> 0 then begin
    ColorArray    := @AlphaArray[pBits.rgbReserved]
    pBits.rgbBlue := ColorArray[pBits.rgbBlue];
    pBits.rgbGreen := ColorArray[pBits.rgbGreen];
    pBits.rgbRed  := ColorArray[pBits.rgbRed];
  end;
  Inc(pBits);
end;
Wie das vorberechnet wird, ist dann egal. (Float, Int8 oder Int16)

Zitat:

Danke das habe ich ja gemacht.
Nee?

Einmal alle Werte mit deiner Variante berechnen, dann nochmal mit 8 und/oder 16
und sie nebeneinander stellen.
Delphi-Quellcode:
for rgbReserved := 0 to 255 do
  for rgbBlue := 0 to 255 do
  begin
    AlphaCoef1 := 255 div rgbReserved; // auch mal zum Spaß die extemen Rundungsfehler
    rgbBlue1 := (rgbBlue * AlphaCoef1);

    AlphaCoef8 := (255 shl 8) div rgbReserved;
    rgbBlue8 := ((rgbBlue * AlphaCoef8) shr 8);

    AlphaCoef16 := (255 shl 16) div rgbReserved;
    rgbBlue16 := ((rgbBlue * AlphaCoef16) shr 16);

    AlphaCoefF := (rgbReserved / 255);
    rgbBlueF := Trunc(rgbBlue / AlphaCoefF); // Trunc statt Round, damit es vergleichbar ist, da DIV/SHR auch abrundet

  //rgbBlueF := Trunc(rgbBlue / (rgbReserved / 255)); // frei nach den mathematischen Regeln auflösen
  //rgbBlueF := Trunc(rgbBlue / rgbReserved * 255);
  //rgbBlueF := Trunc(rgbBlue * 255 / rgbReserved);

    rgbBlueD := (rgbBlue * 255) div rgbReserved;

    AddToMemo(rgbReserved, rgbBlue, rgbBlue1, rgbBlue8, rgbBlue16, rgbBlueF, rgbBlueD);
  end;

Michael II 1. Jun 2017 19:27

AW: Rundungs problem?
 
Zitat:

es geht mir darum ob nun eine Rundungsfehler auftreten kann oder nicht..
Wir verstehen einander nicht. Mir geht's ja auch genau um die möglichen Rundungsfehler.

Du kannst leicht testen, ob Rundungsfehler auftreten, indem du einfach alle möglichen Resultate für alle drei Varianten ausrechnest.

Noch einmal: Da dein Alpha Werte in [0..255] und deine Farbwerte Werte in [0..255] annehmen können, musst du pro Variante genau 256x256 Resultate berechnen (und diese miteinander vergleichen) und weisst danach ganz genau, ob Rundungsfehler auftreten oder nicht. Grund: Du hast dann alle Fälle, welche auftreten können berücksichtigt.

EWeiss 1. Jun 2017 19:33

AW: Rundungs problem?
 
Zitat:

Zitat von Michael II (Beitrag 1373266)
Zitat:

es geht mir darum ob nun eine Rundungsfehler auftreten kann oder nicht..
Wir verstehen einander nicht. Mir geht's ja auch genau um die möglichen Rundungsfehler.

Du kannst leicht testen, ob Rundungsfehler auftreten, indem du einfach alle möglichen Resultate für alle drei Varianten ausrechnest.

Noch einmal: Da dein Alpha Werte in [0..255] und deine Farbwerte Werte in [0..255] annehmen können, musst du pro Variante genau 256x256 Resultate berechnen (und diese miteinander vergleichen) und weisst danach ganz genau, ob Rundungsfehler auftreten oder nicht. Grund: Du hast dann alle Fälle, welche auftreten können berücksichtigt.

Ach so;)
Ja das könnte ich machen.

@himitsu
Danke für die Beispiele.

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:59 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