Skip to content

Commit 0e33520

Browse files
committed
TPointArray.Median: [1,3,5] returned 4 not 3 and [1,3,5,7] returned 5 not 4.
TPointArray.Mean: Use Int64 for Mean sums + added test
1 parent f2df7d9 commit 0e33520

3 files changed

Lines changed: 52 additions & 6 deletions

File tree

Source/simba.res

0 Bytes
Binary file not shown.

Source/simba.vartype_pointarray.pas

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -987,21 +987,26 @@ function TPointArrayHelper.Mean: TPoint;
987987
var
988988
Ptr: PPoint;
989989
Upper: PtrUInt;
990+
SumX, SumY: Int64;
990991
begin
991992
Result := TPoint.ZERO;
992993
if (Length(Self) = 0) then
993994
Exit;
994995

996+
SumX := 0;
997+
SumY := 0;
998+
995999
Ptr := @Self[0];
9961000
Upper := PtrUInt(Ptr) + (Length(Self) * SizeOf(TPoint));
9971001
while (PtrUInt(Ptr) < Upper) do
9981002
begin
999-
Inc(Result.X, Ptr^.X);
1000-
Inc(Result.Y, Ptr^.Y);
1003+
Inc(SumX, Ptr^.X);
1004+
Inc(SumY, Ptr^.Y);
10011005
Inc(Ptr);
10021006
end;
10031007

1004-
Result := Result div Length(Self);
1008+
Result.X := SumX div Length(Self);
1009+
Result.Y := SumY div Length(Self);
10051010
end;
10061011

10071012
function TPointArrayHelper.MinAreaRect: TQuad;
@@ -2783,14 +2788,14 @@ function TPointArrayHelper.Median: TPoint;
27832788

27842789
Mid := Length(Self) div 2;
27852790

2786-
if (Length(Self) mod 2) = 0 then
2791+
if (Length(Self) mod 2) = 1 then
27872792
begin
27882793
Result.X := X[Mid];
27892794
Result.Y := Y[Mid];
27902795
end else
27912796
begin
2792-
Result.X := Round((X[Mid] + X[Mid+1]) / 2);
2793-
Result.Y := Round((Y[Mid] + Y[Mid+1]) / 2);
2797+
Result.X := Round((X[Mid-1] + X[Mid]) / 2);
2798+
Result.Y := Round((Y[Mid-1] + Y[Mid]) / 2);
27942799
end;
27952800
end;
27962801
end;

Tests/tpa_meanmedian.simba

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{$assertions on}
2+
3+
procedure TestMean;
4+
var
5+
arr: TPointArray;
6+
i: Int32;
7+
begin
8+
Assert(TPointArray([]).Mean() = Point(0, 0), 'Mean of empty');
9+
Assert(TPointArray([Point(1, 1), Point(2, 2)]).Mean() = Point(1, 1), 'Mean truncates');
10+
11+
arr := TPointArray.CreateFromBox(TBox.Create(0, 0, 10, 10), True);
12+
Assert(arr.Mean() = Point(5, 5), 'Mean of symmetric box');
13+
arr += Point(1000, 1000);
14+
Assert(arr.Mean() = Point(13, 13), 'Mean should be dragged by outlier');
15+
16+
// check overflowing
17+
SetLength(arr, 2000);
18+
for i := 0 to High(arr) do
19+
arr[i] := Point(2000000, 2000000);
20+
Assert(arr.Mean() = Point(2000000, 2000000), 'Mean overflowed on a large sum');
21+
end;
22+
23+
procedure TestMedian;
24+
var
25+
arr: TPointArray;
26+
begin
27+
Assert(TPointArray([]).Median() = Point(0, 0), 'Median of empty');
28+
Assert(TPointArray([Point(9, 9), Point(1, 1), Point(5, 5)]).Median() = Point(5, 5), 'Median odd');
29+
Assert(TPointArray([Point(1, 1), Point(3, 3), Point(5, 5), Point(7, 7)]).Median() = Point(4, 4), 'Median even');
30+
Assert(TPointArray([Point(0, 10), Point(5, 0), Point(10, 5)]).Median() = Point(5, 5), 'Median is per axis');
31+
32+
arr := TPointArray.CreateFromBox(TBox.Create(0, 0, 10, 10), True);
33+
Assert(arr.Median() = Point(5, 5), 'Median of symmetric box');
34+
arr += Point(1000, 1000);
35+
Assert(arr.Median() = Point(5, 5), 'Median outlier should be unaffected');
36+
end;
37+
38+
begin
39+
TestMean();
40+
TestMedian();
41+
end.

0 commit comments

Comments
 (0)