On 08.06.2023 12:24, Giuliano Colla wrote:

Il 08/06/23 11:58, Ondrej Pokorny via lazarus ha scritto:
All in all, an over-complicated approach with little gain.

The gain would be that you do not add up rounding errors. We can't have fractional pixels, of course, but we may have the exact actual size at design/creation time, and for each different DPI the best approximation to the actual size. If you switch back and forth between two monitors with different DPI the rounding errors remain constant, they don't add up.

You have to consider that for monitor DPI scaling, incrementing series of multiplications like
A * 1.5 * 1.25 * 1.75 * 2.00 * etc * etc
never appear.

You always have a limited count of different resolutions (usually 2) and you always switch between up- and down-scaling. Statistically the Round() function rounds up and down equal sets of float values. So, statistically, the errors cannot add up, but they fix themselves up with the count of up- and down-scaling operations.

Here is my proof for switching between 2 different resolutions from start with 100%:

program Project1;
uses Math;
const
  Resolutions: array[0..3] of Double = (1.25, 1.50, 1.75, 2.00);
var
  R: Double;
  I, F: Integer;
begin
  for R in Resolutions do
    for I := 0 to 1000 do
    begin
      F := I;
      // scale first up and then down
      F := Round(F * R);
      F := Round(F / R);
      if not SameValue(F, I) then
        Writeln(I, ': ', F);
    end;
  ReadLn;
end.

Run the program, and you will se that there is no starting value at 100% that would differ if you scale it up and down.

-------

If you want to test scaling down and up, then there of course there will be a discrepancy between starting and ending value after 1 down- and up-scaling cycle because you lose resolution with the first division. But if you do the same up/down scaling again, you will see that every starting value ended at a well defined pair of values. The values definitely do not grow or shrink with the count of scaling operations.

program Project1;
uses Math;
const
  Resolutions: array[0..3] of Double = (1.25, 1.50, 1.75, 2.00);
var
  R: Double;
  I, F, ErrorCountInMiddleValue, ErrorCountAfterSecondScaling, MiddleValue: Integer;
begin
  ErrorCountInMiddleValue := 0;
  ErrorCountAfterSecondScaling := 0;
  for R in Resolutions do
    for I := 0 to 1000 do
    begin
      F := I;
      // first scale down, then up
      F := Round(F / R);
      F := Round(F * R);
      MiddleValue := F;
      if not SameValue(F, I) then
      begin
        Inc(ErrorCountInMiddleValue);
        // scale first down and then up
        F := Round(F / R);
        F := Round(F * R);

        if not SameValue(F, MiddleValue) then
        begin
          Writeln('Error after second scaling: ', I, ': ', F);
          Inc(ErrorCountAfterSecondScaling);
        end;
      end;
    end;
  Writeln('ErrorCountInMiddleValue: ', ErrorCountInMiddleValue);
  Writeln('ErrorCountAfterSecondScaling: ', ErrorCountAfterSecondScaling);
  ReadLn;
end.

As you can see, there is no starting value that would cause a constantly incrementing or decrementing series of values. Every starting value settles down on a well-defined pair of values after the second scaling.

I consider my arguments as proven. Your suggestion to have a better precision units for sizes doesn't help at all.

---

And even if you found some very rare combination of scaling A -> B -> C -> A of some value X that increments by 1px every time after the whole scaling cycle is performed: who cares that after so many scaling operations the window/column/... width is bigger/smaller by 1px? As I said in the beginning, the default values should not be scaled with this approach, they should be scaled always from a constant value at 100%/96 PPI. That means for them the rounding error problem does not apply. It would apply only for user-defined sizes and there it does not matter because if the size doesn't do it for the user, he can always resize the window/column/ whatever.

Ondrej

--
_______________________________________________
lazarus mailing list
lazarus@lists.lazarus-ide.org
https://lists.lazarus-ide.org/listinfo/lazarus

Reply via email to