Страница 1 из 1

Ускоренная версия функции определения високосного года

СообщениеДобавлено: 15.12.2025 21:49:51
Alexander
Её вначале удалось немного ускорить вручную, а затем этот замысел развил ИИ и вот что получилось.

Для органайзера я использую сейчас её 64 битную версию, но на всякий случай сделал и проверил 16 битную. Она работает ещё немного быстрее и совместима по параметру с функцией FPC SysUtils.IsLeapYear.
Так что вполне кандидат на замещение имеющихся в FPC этих функций. Ускорение в два с гаком раз.

Отдельно функция выглядит так:

Код: Выделить всё
function vg16(y : word) : bytebool; inline;
begin
Exit((y and 3 = 0) and ((y mod 25) <> 0) or (y and 15 = 0));
end;


В составе последней версии органайзера (юнит time.pas): http://soft.self-made-free.ru/GORG64_503.tar.xz
там также есть последние ускорения и для других функций времени, но эта функция ускорена наиболее сильно.

Re: Ускоренная версия функции определения високосного года

СообщениеДобавлено: 16.12.2025 08:45:45
Снег Север
Просто интересно - где может пригодиться ускорение в два раза определения високосного года??? Существуют приложения, где это требуется делать в реальном времени тысячи раз в секунду?

Re: Ускоренная версия функции определения високосного года

СообщениеДобавлено: 16.12.2025 09:10:56
Alexander
Даже если функция используется один раз в секунду - это выигрыш, а не проигрыш. Процессор-то при этом отдыхает. А где-то и большие данные обрабатываются на эту тему - функция на самом часто используемая. Каждая ускоренная в два раза функция либо удваивает мощность процессора, либо уполовинивает энергопотребление компьютера - как на это смотреть.

Пользователи, кстати, могут здесь написать, насколько она улучшила их программы.

Re: Ускоренная версия функции определения високосного года

СообщениеДобавлено: 16.12.2025 10:44:53
Снег Север
Да мне не жалко, программисты развлекаются. Но вот насчет частого использования, да ещё в приложениях, а не серверами - это как-то сомнительно.

Re: Ускоренная версия функции определения високосного года

СообщениеДобавлено: 17.12.2025 10:32:33
iskander
Alexander писал(а):Её вначале удалось немного ускорить вручную, а затем этот замысел развил ИИ и вот что получилось.

Для органайзера я использую сейчас её 64 битную версию, но на всякий случай сделал и проверил 16 битную. Она работает ещё немного быстрее и совместима по параметру с функцией FPC SysUtils.IsLeapYear.
Так что вполне кандидат на замещение имеющихся в FPC этих функций. Ускорение в два с гаком раз.

Отдельно функция выглядит так:
Код: Выделить всё
function vg16(y : word) : bytebool; inline;
begin
Exit((y and 3 = 0) and ((y mod 25) <> 0) or (y and 15 = 0));
end;


Емнип, оптимизатор FPC-3.2.2 умеет заменять целочисленное деление на константу умножением только для оператора DIV, но не умеет для MOD:
Код: Выделить всё
program test;
{$mode objfpc}{$H+}
uses
  SysUtils, StopWatch;

function IsLeapYear1(y: Word): Boolean;
begin
  Result := (y and 3 = 0) and (y mod 25 <> 0) or (y and 15 = 0);
end;

{$push}{$B+}
function IsLeapYear2(y: Word): Boolean;
begin
{$if Fpc_FullVersion < 30301}
  Result := (y and 3 = 0) and (y - (y div 25)*25 <> 0) or (y and 15 = 0);
{$else}
  Result := (y and 3 = 0) and (y mod 25 <> 0) or (y and 15 = 0);
{$endif}
end;
{$pop}

const
  DataSize = 10000000;
var
  a: array of Word;
  i: Integer;
  sw: TStopWatch;
begin
  WriteLn('FPC-',{$I %FpcVersion%},' ', {$I %FPCTargetCPU%});
  Randomize;
  SetLength(a, DataSize);
  for i := 0 to High(a) do
    a[i] := Word(Random(10000));

  sw := TStopWatch.StartNew;
  for i := 0 to High(a) do
    IsLeapYear(a[i]);  //built-in
  sw.Stop;
  WriteLn('IsLeapYear: ', sw.ElapsedMilliseconds.ToString+' ms.');

  sw := TStopWatch.StartNew;
  for i := 0 to High(a) do
    IsLeapYear1(a[i]);
  sw.Stop;
  WriteLn('IsLeapYear1: ', sw.ElapsedMilliseconds.ToString+' ms.');

  sw := TStopWatch.StartNew;
  for i := 0 to High(a) do
    IsLeapYear2(a[i]);
  sw.Stop;
  WriteLn('IsLeapYear2: ', sw.ElapsedMilliseconds.ToString+' ms.');
end.

>>>
Код: Выделить всё
FPC-3.2.2 x86_64
IsLeapYear: 153,5927 ms.
IsLeapYear1: 60,2301 ms.
IsLeapYear2: 25,8963 ms.

А транковый 3.3.1 научился
Код: Выделить всё
FPC-3.3.1 x86_64
IsLeapYear: 38,0221 ms.
IsLeapYear1: 38,3202 ms.
IsLeapYear2: 17,6842 ms.

А для x86 всё несколько менее драматично
Код: Выделить всё
FPC-3.2.2 i386
IsLeapYear: 55,5314 ms.
IsLeapYear1: 53,1172 ms.
IsLeapYear2: 27,5213 ms.

Код: Выделить всё
FPC-3.3.1 i386
IsLeapYear: 40,2913 ms.
IsLeapYear1: 41,8065 ms.
IsLeapYear2: 18,6108 ms.