powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Generics, а собственно как сравнить элементы <T> ?
24 сообщений из 49, страница 2 из 2
Generics, а собственно как сравнить элементы <T> ?
    #40032990
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На предыдущей картинке промахнулся с именами переменных, пардон муа.
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40032994
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey
в хелпере оператор декларировать нельзя

Но, если переключиться в диалект FPC, то можно декларировать глобальные операторы, и таким образом закрыть и этот вопрос.
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40032998
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для наглядности сделал ещё метод ToString. Операторы вынес в отдельный модуль с диалектом FPC, написал тайпхелперы с методом ToString для используемых типов (они тоже в отдельном модуле).
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033010
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Страдалецъ
авторТо есть типа через TComparer<T>.Default было сложнее, да? )

Я просто не понял как это делать, а когда попробовал сделать функцию Random через дженерики снова наступил на те-же грабли и просто бросил. Если не сложно, то покажите на моем конечном коде, как это будет через дженерики.

Я не знаю как работают шаблоны в С++
Но я знаю, что в Delphi под T может быть любой тип, в том числе такой, для которого нет операторов сравнения
Поэтому то, что ты ожидаешь в Delphi не работает

С другой стороны есть дефолтный компаратор
X-Cite показал отличный пример, как его юзать. Я бы только проинициализировал его в классовом конструкторе. Но это детали

Если интересует высокая производительность - то великолепный пример показал Казанцев Алексей
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033027
Страдалецъ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: pascal
1.
Min := TValue.From<T>(FMin).AsInt64();


Чего-то не выходит каменный цветок. Не хочет работать такая конструкция в XE 10
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033029
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU
Если интересует высокая производительность - то великолепный пример показал Казанцев Алексей
Я вот, кстати,.не уверен что его код заметно быстрей чем TComparer<T>.Default.Compare.
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033031
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat,

Не уверен - проверь. Например, первый кейс дельфя должна развернуть, задействовав под каждый из типов только одну ветку кода, т.к. интринсинк GetTypeKind резолвится в компайлтайме.
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033032
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
юю
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033033
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey,

Код
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
program Project5;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  SysUtils, TypInfo, Diagnostics, Generics.Defaults;

type

TTest<T> = class
  Cmp: IComparer<T>;
  function IsMore1(T1,T2: T): boolean; inline;
  function IsMore2(T1,T2: T): boolean; inline;
  constructor Create;
end;

constructor TTest<T>.Create;
begin
  Cmp:=TComparer<T>.Default;
end;

function TTest<T>.IsMore1(T1,T2: T): boolean;
begin
  Result:=Cmp.Compare(T1, T2)>0;
end;

function TTest<T>.IsMore2(T1,T2: T): boolean;
begin
   case GetTypeKind(T) of
    tkInteger : case PTypeInfo(TypeInfo(T)).TypeData.OrdType of
                 otSByte : Result := ShortInt((@T1)^) >= ShortInt((@T2)^);
                 otUByte : Result := Byte((@T1)^) >= Byte((@T2)^);
                 otSWord : Result := SmallInt((@T1)^) >= SmallInt((@T2)^);
                 otUWord : Result := Word((@T1)^) >= Word((@T2)^);
                 otSLong : Result := Integer((@T1)^) >= Integer((@T2)^);
                 otULong : Result := Cardinal((@T1)^) >= Cardinal((@T2)^);
                else
                 Error(reAssertionFailed);
                end;

    tkInt64   : Result := Int64((@T1)^) >= Int64((@T2)^);

    tkFloat   : if PTypeInfo(TypeInfo(T)).TypeData.FloatType = ftDouble then
                 Result := Double((@T1)^) >= Double((@T2)^)
                else
                 Error(reAssertionFailed);
   else
    Error(reAssertionFailed);
   end;
end;

begin
  var Test := TTest<Integer>.Create;
  var T:=TStopwatch.StartNew;
  for var i:=0 to 100000000 do begin
    Test.IsMore1(1,2);
  end;
  var R1:=T.ElapsedMilliseconds;

  T:=TStopwatch.StartNew;
  for var i:=0 to 100000000 do begin
    Test.IsMore2(1,2);
  end;
  var R2:=T.ElapsedMilliseconds;

  Writeln(R1,' ',R2,' ',Trunc(R1/R2*100));

  ReadLn;
end.


Чертез TComparer<T>.Default - 188 мс.
Через GetTypeKind(T) - 301 мс.
62%

Через компайрер вышло на треть быстрей.
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033034
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В 64-х битах разница меньше, но все одно 77%.

Delphi 10.4.
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033039
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat,

Отличный тест

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
program Project1;

{$APPTYPE CONSOLE}
{$U-}{$V+}{$B-}{$X+}{$T+}{$P+}{$H+}{$J-}{$Z1}{$A4}
{$O+}{$R-}{$I-}{$Q-}{$W-}

{$R *.res}

uses
  SysUtils, Math, TypInfo, Diagnostics, Generics.Defaults;

type

  TTest<T> = class
  private
    class var
      FCmp: IComparer<T>;
      FIsSigned: Boolean;
      FIsDouble: Boolean;

    class constructor ClassCreate;
  public
    function IsMore1(const T1, T2: T): Boolean; inline;
    function IsMore2(const T1, T2: T): Boolean; inline;
  end;

class constructor TTest<T>.ClassCreate;
var
  LTypeData: PTypeData;
begin
  FCmp := TComparer<T>.Default;

  LTypeData := PTypeInfo(TypeInfo(T)).TypeData;
  case GetTypeKind(T) of
    tkInteger:
    begin
      FIsSigned := (LTypeData.OrdType in [otSByte, otSWord, otSLong]);
    end;
    tkInt64:
    begin
      FIsSigned := (LTypeData.MinInt64Value < LTypeData.MaxInt64Value);
    end;
    tkFloat:
    begin
      FIsDouble := (LTypeData.FloatType = ftDouble);
    end;
  end;
end;

function TTest<T>.IsMore1(const T1, T2: T): Boolean;
begin
  Result := (FCmp.Compare(T1, T2) >= 0);
end;

function TTest<T>.IsMore2(const T1, T2: T): Boolean;
begin
   case GetTypeKind(T) of
     tkInteger:
     begin
       case SizeOf(T) of
         SizeOf(Byte):
         begin
           if (FIsSigned) then
             Result := PShortInt(@T1)^ >= PShortInt(@T2)^
           else
             Result := PByte(@T1)^ >= PByte(@T2)^;
         end;
         SizeOf(Word):
         begin
           if (FIsSigned) then
             Result := PSmallInt(@T1)^ >= PSmallInt(@T2)^
           else
             Result := PWord(@T1)^ >= PWord(@T2)^;
         end;
       else
         if (FIsSigned) then
           Result := PInteger(@T1)^ >= PInteger(@T2)^
         else
           Result := PCardinal(@T1)^ >= PCardinal(@T2)^;
       end;
     end;
     tkInt64:
     begin
       if (FIsSigned) then
         Result := PInt64(@T1)^ >= PInt64(@T2)^
       else
         Result := PUInt64(@T1)^ >= PUInt64(@T2)^;
     end;
     tkFloat:
     begin
       case SizeOf(T) of
         SizeOf(Single):
         begin
           Result := PSingle(@T1)^ >= PSingle(@T2)^;
         end;
         {$if SizeOf(Extended) > SizeOf(Double)}
         SizeOf(Extended):
         begin
           Result := PExtended(@T1)^ >= PExtended(@T2)^;
         end;
         {$ifend}
       else
         if (FIsDouble) then
           Result := PDouble(@T1)^ >= PDouble(@T2)^
         else
           Result := PInt64(@T1)^ >= PInt64(@T2)^;
       end;
     end;
   else
     raise Exception.Create('Error Message');
   end;
end;

begin
  var Test := TTest<Integer>.Create;
  var T := TStopwatch.StartNew;
  for var i := 0 to 100000000 do
  begin
    Test.IsMore1(1, 2);
  end;
  var R1 := T.ElapsedMilliseconds;

  T := TStopwatch.StartNew;
  for var i := 0 to 100000000 do
  begin
    Test.IsMore2(1, 2);
  end;
  var R2 := T.ElapsedMilliseconds;

  Writeln('Default: ', R1, 'ms');
  Writeln('Inline: ', R2, 'ms');
  Writeln('Profit: x', (R1 / R2):0:2);

  Writeln;
  Write('Press Enter to quit');
  ReadLn;
end.


Код: plaintext
1.
2.
Default: 256ms
Inline: 176ms
Profit: x1.45
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033041
Bred eFeM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU, плюсик! тебе в карму ))
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033042
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Bred eFeM,

Ееееее )
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033044
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat
Через компайрер вышло на треть быстрей.

Во-первых, ты изменил задачу. ТС сравнивает вхождение числа в диапазон, ты же делаешь только одно сравнение, чем ставишь компарер в более выгодные условия. Во-вторых, тестируешь только заведомо худший вриант для ручной реализации. Если вернуть задачу к первоначальному варианту и сравнивать вхождение числа, то вариант с компарером для типа Integer, будет ни чем не лучше ручного варианта (который не самый оптимальный), а для типа Int64 будет хуже. А что будет при оптимизированном ручном варианте, уже показали :)
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033045
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И нужно понимать, что речь даже не столько о производительности была, сколько об "удобстве" дельфийских дженериков. Тут ещё хорошо, что требуется только банальное сравнение, для которого у дельфей есть готовая реализция, а если потребуется что-то более сложное, то всё равно придётся всё пилить руками.
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033057
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Так извращаться только ради того что бы получить сравнимую производительность с дефолтом.

Извращенцы.

Вы еще на ассемблер это все перепишите. :)
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033059
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat,

Ассемблер в дженериках не работает :)
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033060
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU,

А ты залинкуй через указатели!
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033061
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat,

Но вообще я изначально за дефолтный компаратор был
Это ты про производительность )
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033062
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU
это ты про производительность )

Ы-ы-ы-ы!
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033064
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat,

А кто тесты начал фигачить )
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033065
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU,

Меня заставили. Это все вы виноваты!
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033072
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Страдалецъ
Код: pascal
1.
Min := TValue.From<T>(FMin).AsInt64();


Чего-то не выходит каменный цветок. Не хочет работать такая конструкция в XE 10


Должна вроде, что пишет то?
...
Рейтинг: 0 / 0
Generics, а собственно как сравнить элементы <T> ?
    #40033077
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat
Так извращаться только ради того что бы получить сравнимую производительность с дефолтом.

Не ради производительности же, ради механики.
...
Рейтинг: 0 / 0
24 сообщений из 49, страница 2 из 2
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Generics, а собственно как сравнить элементы <T> ?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]