Конвертация Int64 с разделителем групп разрядов: неужели?!)

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение Alex2013 » 07.02.2023 20:46:16

iskander писал(а):
Alex2013 писал(а):Чисто как вариант "псевдо оптимизации"
( Возможно где-то напутал "с циферками" но просто "как идея" )
Код: Выделить всё
  function IntToStrTS(const AValue: SizeUInt): string;
  var i,J, vSrcLen,  vSCount, vResLen: integer ; //!
  STmp: string;
  begin
    Str(AValue, STmp); // всеравно два раза память выделяется
    vSrcLen :=  STmp.Length;
    vSCount:= ((vSrcLen - 1) div 3) ;
    vResLen := vSrcLen +vSCount;
    SetLength(Result, vResLen);
  J:=3; For I:=1 to vSCount do begin
  If i = vSCount  then J:=vResLen - vSCount*3 ;
  // Чуть криво но работать по идее будет
  if J<>0 then begin
   Move( STmp[vResLen-(i*3)],Result[vResLen-(i*4)+1],J); // ???
     Result[vResLen-(i*4)]:=' ';// или  FormatSettings.ThousandSeparator
    end
  end
  end;

...


Ага, кажется, исправил. Ещё было бы неплохо, если бы она какой-нибудь результат возвращала.

Исправил но не все ( Вовремя "дежурного блэкаута" попытался отладить но винда не любит повторов исключений , а часто перезагружаться АКБ не позволяет ) В начале думал что 64 разряда так влияют, но и в 32 тоже заглючило ( что-то с адресацией нездоровое началось ).
Для проверки написал буквально следующее.
Move( STmp[1],Result[1],1);Move( STmp[2],Result[2],1);Move( STmp[3],Result[3],1);
Один раз нормально сработало добавил
For I:=1 to vSrcLen do Move( STmp[i],Result[i],1);
Начало все путать местами причем и первая строчка тоже перестала работать.
Есть идея что это все же UTF8 глючит или оптимизация под "многоядерность" вылезла.
( но больше всего похоже на банальный "зомби-процесс" весящий в памяти который перехватывает обработку у исправленных версии после нескольких плохо обработанных исключений, и в результате все попытки экстренно править код только все портят )
Последний раз редактировалось Alex2013 08.02.2023 14:47:14, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2937
Зарегистрирован: 03.04.2013 11:59:44

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение avmaksimov » 07.02.2023 23:35:22

Alex2013 писал(а):Есть идея что это все же UTF8 глючит или оптимизация под "многоядерность" вылезла.
( но больше всего похоже на банальный "зомби-процесс" весящий в памяти который перехватывает обработку у исправленных версии после нескольких плохо обработанных исключений, и в результате все попытки экстренно править код только все протят )

Вы бы ещё квантовой неопределённостью обосновали.

Доделал я тот метод с Move'ом.
Код: Выделить всё
function IntToStrTSMove(const AValue: Int64): string;
  var i, vSrcLen, vSrcI, vResLen, vTSCount: byte;
    sTmp: string;
begin
  Str(AValue, sTmp);
  vSrcLen := sTmp.Length;

  vTSCount := (vSrcLen - 1) div 3;

  if vTSCount = 0 then
    Exit(sTmp);

  vResLen := vSrcLen + vTSCount; 

  SetLength(Result, vResLen);

  vSrcI := vSrcLen - 2;
  for i := vTSCount downto 1 do
    begin
      Move(sTmp[vSrcI], Result[vSrcI + i], 3);
      Result[vSrcI + i - 1] := FormatSettings.ThousandSeparator;
      if i <> 1 then
        Dec(vSrcI, 3)
      else
        Move(sTmp[1], Result[1], vSrcI - 1);
    end;
end;   


И решил потестить всё вместе. Получилось, что первый метод лучше всего. С Move ещё и медленнее работает, правда, только на полшишки. FloatToStrF работает в 3 раза медленнее. Тесты: https://disk.yandex.ru/d/7wWk329zRFMXUg

Была мысль ещё своё написать преобразование сразу из числа в строку с разделителем, но уже что-то лень)). Может, завтра). Но есть более важные дела).

Но что странно. Глюка с преобразованием из Integer в Extended нет в Linux, а вот под Windows есть. Почему?)) Притом, на виртуалке VBox около тысячных, как и писал раньше. А на чистой тачке меньше - десятки или иногда сотни.
avmaksimov
новенький
 
Сообщения: 21
Зарегистрирован: 17.10.2010 12:38:54

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение iskander » 08.02.2023 00:28:19

А что насчёт вот такого варианта?
Код: Выделить всё
function GetDecimalStrLen(AValue: SizeUInt): Integer; inline;
begin
{$if defined(CPU16)}
    case AValue of
      0..9: Result := 1;
      10..99: Result := 2;
      100..999: Result := 3;
      1000..9999: Result := 5;
    else
      Result := 6;
    end;
{$elseif defined(CPU32)}
    case AValue of
      0..9: Result := 1;
      10..99: Result := 2;
      100..999: Result := 3;
      1000..9999: Result := 5;
      10000..99999: Result := 6;
      100000..999999: Result := 7;
      1000000..9999999: Result := 9;
      10000000..99999999: Result := 10;
      100000000..999999999: Result := 11;
    else
      Result := 13;
    end;
{$else}
    case AValue of
      0..9: Result := 1;
      10..99: Result := 2;
      100..999: Result := 3;
      1000..9999: Result := 5;
      10000..99999: Result := 6;
      100000..999999: Result := 7;
      1000000..9999999: Result := 9;
      10000000..99999999: Result := 10;
      100000000..999999999: Result := 11;
      1000000000..9999999999: Result := 13;
      10000000000..99999999999: Result := 14;
      100000000000..999999999999: Result := 15;
      1000000000000..9999999999999: Result := 17;
      10000000000000..99999999999999: Result := 18;
      100000000000000..999999999999999: Result := 19;
      1000000000000000..9999999999999999: Result := 21;
      10000000000000000..99999999999999999: Result := 22;
      100000000000000000..999999999999999999: Result := 23;
      1000000000000000000..9999999999999999999: Result := 25;
    else
      Result := 26;
    end;
{$endif}
end;

function IntToStrTSv2(AValue: SizeUInt; ASeparator: Char): string;
const
  Decs: array[0..9] of Char = ('0','1','2','3','4','5','6','7','8','9');
var
  Q: SizeUInt;
  I: Integer;
  p: PChar;
begin
  Result := '';
  SetLength(Result, GetDecimalStrLen(AValue));
  p := PChar(Result);

  I := Length(Result)-1;
  while I > 2 do begin
    Q := AValue div 10;
    p[I] := Decs[AValue - Q * 10];

    AValue := Q div 10;
    p[I-1] := Decs[Q - AValue * 10];

    Q := AValue div 10;
    p[I-2] := Decs[AValue - Q * 10];
    AValue := Q;

    p[I-3] := ASeparator;
    Dec(I, 4);
  end;
  case I of
    0: p^ := Decs[AValue];
    1:
      begin
        Q := AValue div 10;
        p[I] := Decs[AValue - Q * 10];

        p^ := Decs[Q];
      end;
    2:
      begin
        Q := AValue div 10;
        p[I] := Decs[AValue - Q * 10];

        AValue := Q div 10;
        p[I-1] := Decs[Q - AValue * 10];

        p^ := Decs[AValue];
      end;
  else
  end;
end;
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение Seenkao » 08.02.2023 01:10:22

avmaksimov, я тоже занимался, только оптимизацией в скорость Pascal.

А потом всё сделал на ассемблере.
Сам топик на gamedev.

Добавлено спустя 4 минуты 4 секунды:
Re: Конвертация Int64 с разделителем групп разрядов: неужели?!)
Числа проще переводить. Просто надо делить для десятичных, а для остальных сдвигать. Везде брать остаток.
Я вот за числа с плавающей точкой так и не взялся... )))

Добавлено спустя 8 минут 35 секунд:
Re: Конвертация Int64 с разделителем групп разрядов: неужели?!)
avmaksimov писал(а):Вы неверно поняли. Речь про разделить тысяч. Читать строку "1 235 656 788" приятнее и понятнее, чем "1235656788".

и я тоже не верно понял...
Но вот вопрос встаёт, её ведь только читать нужно? Тогда это надо делать только при выводе, а не при переводе числа в строку. Иначе будет лишнее преобразование обратно в число "без пробелов".
А для изменения строки достаточно найти точку/запятую и если нашли её или не нашли, просто влепить пробелы при выводе числа от местоположения точки, или с конца числа, если точки нет.
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение avmaksimov » 08.02.2023 09:02:13

Seenkao писал(а):avmaksimov, я тоже занимался, только оптимизацией в скорость Pascal.

Посмотрел ваш код. "Много буковок") Скажите, не пробовали ли вы через "чистую математику"?) Я имею в виду подсчитать число символов в будущей строке через trunc(log10(number))+1, а далее, как и полагается записывать с конца (хотя можно и с начала) увеличивая (или уменьшая, если сначала) степень числа 10? Не будет ли это быстрее вашего кода? Что быстрее ваш код или библиотечный IntToStr?
Seenkao писал(а):Re: Конвертация Int64 с разделителем групп разрядов: неужели?!)
avmaksimov писал(а):Вы неверно поняли. Речь про разделить тысяч. Читать строку "1 235 656 788" приятнее и понятнее, чем "1235656788".

и я тоже не верно понял...
Но вот вопрос встаёт, её ведь только читать нужно? Тогда это надо делать только при выводе, а не при переводе числа в строку. Иначе будет лишнее преобразование обратно в число "без пробелов".
А для изменения строки достаточно найти точку/запятую и если нашли её или не нашли, просто влепить пробелы при выводе числа от местоположения точки, или с конца числа, если точки нет.

Я честно говоря, снова не понял, почему вы не поняли, если я уже другому человеку сказал, что тот неверно понял)))) Какая точка в дробной части? Какая замена чего-либо из IntToStr - нечего менять. Если бы было, я бы не заморочился). Я и удивился, что нет лёгкого способа решения задачи, кроме как смириться с потерей части числа при конвертации в extended. Если есть, ткните).
Аналогично не понял ваши мысли про хранение и преобразование.. Ну как бы тут не студенты вроде собрались - все понимают, что для работы нужно работать с числом, а выводить для человека только результат. Или есть те, что хранят числа в строке (притом предварительно отформатируют их, чтобы жизнь мёдом не казалась)), а потом ещё их и складывают, кроме школяров?)))
avmaksimov
новенький
 
Сообщения: 21
Зарегистрирован: 17.10.2010 12:38:54

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение Alex2013 » 08.02.2023 13:26:07

avmaksimov писал(а):Вы бы ещё квантовой неопределённостью обосновали.

Попробуйте объяснить сбой в индексации хоть как-то проще ... Сбойная память ? (Заметил бы) Вирус-троян-"шутка юмора пиратской винды"? (Тоже сомнительно) Глючный проц на старом дешевом ноте? (Тоже мало вероятно ) :roll: Глюк отладчика в лазере ? ( Возможно но странно )
avmaksimov писал(а):И решил потестить всё вместе. Получилось, что первый метод лучше всего. С Move ещё и медленнее работает, правда, только на полшишки. FloatToStrF работает в 3 раза медленнее. Тесты: https://disk.yandex.ru/d/7wWk329zRFMXUg

Не правда ваша ! :D
Изображение
Вот FloatToStrF действительно отстал и заметно, а метод Move при работе с более длинным числом не много но быстрее.
Последний раз редактировалось Alex2013 08.02.2023 13:45:21, всего редактировалось 2 раз(а).
Alex2013
долгожитель
 
Сообщения: 2937
Зарегистрирован: 03.04.2013 11:59:44

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение avmaksimov » 08.02.2023 13:39:22

Alex2013 писал(а):Не правда ваша ! :D
Изображение
Вот FloatToStrF действительно отстал и заметно, а метод Move при работе с более длинным числом не много но быстрее.

А вы пробовали со значением по умолчанию? Оно же больше? Результат какой? Если можете, проверьте на разных компах, но думаю, дело уже именно в процессорах и ОСи) Я проверял, в основном, на Убунте. Проверю позже на Винде.
avmaksimov
новенький
 
Сообщения: 21
Зарегистрирован: 17.10.2010 12:38:54

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение Alex2013 » 08.02.2023 14:16:29

avmaksimov писал(а):А вы пробовали со значением по умолчанию? Оно же больше? Результат какой? Если можете, проверьте на разных компах, но думаю, дело уже именно в процессорах и ОСи) Я проверял, в основном, на Убунте. Проверю позже на Винде.

Пробовал, но там что угодно мерит только не эту процедуру. НЕ ТО там число большое ( итераций много, а число 5 знаков разумеется тема "балочной передачи данных" нераскрыта ) И вообще мой вариант основным не про скорость ( разница по-любому мизерная ), а про компактность кода . ( Меньше лишних движений меньше переменных по идее больше надежность ) и просто как альтернатива .
Последний раз редактировалось Alex2013 08.02.2023 14:49:15, всего редактировалось 3 раз(а).
Alex2013
долгожитель
 
Сообщения: 2937
Зарегистрирован: 03.04.2013 11:59:44

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение iskander » 08.02.2023 14:27:56

В общем, пока сам себя не похвалишь, никто и не догадается. :)
Мне было влом городить окошки, так что
Код: Выделить всё
program test;

{$mode objfpc}{$H+}

uses
  SysUtils;

function GetStrLen(AValue: SizeUInt): Integer; inline;
begin
{$if defined(CPU16)}
    case AValue of
      0..9: Result := 1;
      10..99: Result := 2;
      100..999: Result := 3;
      1000..9999: Result := 5;
    else
      Result := 6;
    end;
{$elseif defined(CPU32)}
    case AValue of
      0..9: Result := 1;
      10..99: Result := 2;
      100..999: Result := 3;
      1000..9999: Result := 5;
      10000..99999: Result := 6;
      100000..999999: Result := 7;
      1000000..9999999: Result := 9;
      10000000..99999999: Result := 10;
      100000000..999999999: Result := 11;
    else
      Result := 13;
    end;
{$else}
    case AValue of
      0..9: Result := 1;
      10..99: Result := 2;
      100..999: Result := 3;
      1000..9999: Result := 5;
      10000..99999: Result := 6;
      100000..999999: Result := 7;
      1000000..9999999: Result := 9;
      10000000..99999999: Result := 10;
      100000000..999999999: Result := 11;
      1000000000..9999999999: Result := 13;
      10000000000..99999999999: Result := 14;
      100000000000..999999999999: Result := 15;
      1000000000000..9999999999999: Result := 17;
      10000000000000..99999999999999: Result := 18;
      100000000000000..999999999999999: Result := 19;
      1000000000000000..9999999999999999: Result := 21;
      10000000000000000..99999999999999999: Result := 22;
      100000000000000000..999999999999999999: Result := 23;
      1000000000000000000..9999999999999999999: Result := 25;
    else
      Result := 26;
    end;
{$endif}
end;

function IntToStrTSv2(AValue: SizeUInt; ASeparator: Char): string;
var
  Q: SizeUInt;
  I: Integer;
  p: PChar;
begin
  Result := '';
  SetLength(Result, GetStrLen(AValue));
  p := PChar(Result);

  I := Length(Result)-1;
  while I > 2 do begin
    Q := AValue div 10;
    p[I] := Char(AValue - Q * 10 + Ord('0'));

    AValue := Q div 10;
    p[I-1] := Char(Q - AValue * 10 + Ord('0'));

    Q := AValue div 10;
    p[I-2] := Char(AValue - Q * 10 + Ord('0'));
    AValue := Q;

    p[I-3] := ASeparator;
    Dec(I, 4);
  end;
  case I of
    0: p^ := Char(AValue + Ord('0'));
    1:
      begin
        Q := AValue div 10;
        p[I] := Char(AValue - Q * 10 + Ord('0'));

        p^ := Char(Q + Ord('0'));
      end;
    2:
      begin
        Q := AValue div 10;
        p[I] := Char(AValue - Q * 10 + Ord('0'));

        AValue := Q div 10;
        p[I-1] := Char(Q - AValue * 10 + Ord('0'));

        p^ := Char(AValue + Ord('0'));
      end;
  else
  end;
end;

function IntToStrTSv1(const AValue: SizeUInt): string;
var i, vSrcLen, vSrcI, vSrcNumberNo, vResLen: byte;
begin
  Str(AValue, Result);
  vSrcLen := Result.Length;

  vResLen := vSrcLen + ((vSrcLen - 1) div 3);
  SetLength(Result, vResLen);

  vSrcI := vResLen;
  vSrcNumberNo := 1;

  for i:= vSrcLen downto 1 do
    begin
      Result[vSrcI] := Result[i];
      Dec(vSrcI);
      if(vSrcNumberNo <> vSrcLen) and (vSrcNumberNo mod 3 = 0) then
        begin
          Result[vSrcI] := FormatSettings.ThousandSeparator;
          Dec(vSrcI);
        end;
      Inc(vSrcNumberNo);
    end;
end;

function IntToStrTSvMove(const AValue: SizeUInt): string;
var
  i, vSrcLen,  vSCount, vResLen: integer; //!
  STmp: string;
begin
  Str(AValue, STmp); // всеравно два раза память выделяется
  vSrcLen := STmp.Length;
  vSCount := ((vSrcLen - 1) div 3);
  vResLen := vSrcLen + vSCount;
  SetLength(Result, vResLen);
  for I := 1 to vSCount do begin
// Чуть криво но работать по идее будет
      Move(STmp[vSrcLen - (i*3) + 1], Result[vResLen - (i*4) + 2], 3); // ???
      Result[vResLen - (i*4)+1] := FormatSettings.ThousandSeparator;
  end;
  Move(STmp[1], Result[1], vSrcLen - vSCount*3);
end;

var
  a: array of SizeUInt;

procedure TestIntToStrTSv1;
var
  Start: Qword;
  I: Integer;
  s: string;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    s := IntToStrTSv1(a[I]);
  WriteLn('IntToStrTSv1:    ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

procedure TestIntToStrTSv2;
var
  I: Integer;
  s: string;
  Start: Qword;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    s := IntToStrTSv2(a[I], FormatSettings.ThousandSeparator);
  WriteLn('IntToStrTSv2:    ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

procedure TesrIntToStrTSvMove;
var
  Start: Qword;
  I: Integer;
  s: string;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    s := IntToStrTSvMove(a[I]);
  WriteLn('IntToStrTSvMove: ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

procedure TestStr;
var
  I: Integer;
  s: string;
  Start: Qword;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    Str(a[I], s);
  WriteLn('Str:    ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

procedure TestStrv2;
var
  I: Integer;
  s: string;
  Start: Qword;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    s := Strv2(a[I]);
  WriteLn('StrV2:    ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

const
  NumCount = 5000000;

var
  I: Integer;

begin
  Randomize;
  DefaultFormatSettings.ThousandSeparator := ' ';

  SetLength(a, NumCount);
  for I := 0 to High(a) do
    a[I] := Random(High(Int64));

  TestIntToStrTSv1;
  TestIntToStrTSv2;
  TesrIntToStrTSvMove;

  ReadLn;
end.

компилировалась в режиме релиза.
Результаты:
Код: Выделить всё
IntToStrTSv1:    624
2 749 089 333 916 624 192

IntToStrTSv2:    327
2 749 089 333 916 624 192

IntToStrTSvMove: 748
2 749 089 333 916 624 192
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение Seenkao » 08.02.2023 14:30:24

avmaksimov писал(а):Скажите, не пробовали ли вы через "чистую математику"?)

ну у меня как раз "чистая математика". Сделать выборку для всех символов, все разом перевести в значение, а потом сложить... Это может быть быстрее только для больших чисел, а в большинстве своём мы до миллиона не так часто доходим. Я далеко не уверен, что будет быстрее.
Я больше склоняюсь к тому, чтоб эту функцию можно было использовать в многопоточке, и не важно используется она уже где-то или нет. Но пока не занимался этим.

avmaksimov писал(а):Что быстрее ваш код или библиотечный IntToStr?

Проверил, мой быстрее. А тот, что на ассемблере, ещё быстрее, потому что там куча лишних действий убрано.
И, да
avmaksimov писал(а):Предложил на FPC и один из собратьев предложил похожий модуль: http://svn.code.sf.net/p/flyingsheep/co ... fsiconv.pp.

он быстрее этого кода.

(Человек делавший тот код, не захотел его оптимизировать в скорость. Почему? Я не знаю. Но за счёт его кода, я ускорил свой и понял как можно убрать лишние вычисления которые вносит компилятор FPC.
Ну и приходится быть зависимым от кодировки символов. Если кодировка страницы неправильно выставлена, то очень сильно может потеряться скорость.)
нет, это другой код, очень похожий.

avmaksimov писал(а):Я честно говоря, снова не понял, почему вы не поняли, если я уже другому человеку сказал, что тот неверно понял))))

потому что я прочитал тот пост позже. ))) А до этого думал про обычный перевод.

avmaksimov писал(а):Какая точка в дробной части?

Я про числа с плавающей точкой (хотя использовать можно для всех). Если число уже переведено в строку, то достаточно разделитель найти и воткнуть пробелы по местам.

avmaksimov писал(а):Ну как бы тут не студенты вроде собрались - все понимают, что для работы нужно работать с числом, а выводить для человека только результат.

лучше по себе не судить. Я очень часто встречаюсь, где люди хранят числа в текстовом варианте. Не все тут программисты и не все понимают, что это лишние действия. ))) Не в обиду им!

avmaksimov, давай глянем...
iskander писал(а):А что насчёт вот такого варианта?

выдёргиваем нужное из его кода:
Код: Выделить всё
const
  Decs: array[0..9] of Char = ('0','1','2','3','4','5','6','7','8','9');

и делаем заново:
Код: Выделить всё
const
  DecTable: array[0..9] of Char = ('0','1','2','3','4','5','6','7','8','9');

function IntToStrNew(Value: Int64): string;
var
  _Res: array[0..26] of Char;
  i, j, n: int64;
  minus: boolean = false;
label
  GoEnd;
begin
  if Value = 0 then
  begin
    Result := '0';
    exit;
  end;
  Result := '';
  n := 0;
  j := 0;
  if Value < 0 then
  begin
    minus := true;
    Value := abs(Value + 1);
  end;
  // тут надо сделать шаг, если значение было минусовое
  if minus then
  begin
    i := Value mod 10 + 1;
    Value := Value div 10;
    if i > 9 then
    begin
      inc(Value);
      _Res[j] := '0';
    end
    else
      _Res[j] := DecTable[i];
    inc(j);
    inc(n);
    if Value = 0 then
      goto GoEnd;
  end;
  while Value > 9 do
  begin
    i := Value mod 10;
    Value := Value div 10;
    _Res[j] := DecTable[i];
    inc(j);
    inc(n);
    if n = 3 then
    begin
      _Res[j] := ' ';
      inc(j);
      n := 0;
    end;
  end;
  _Res[j] := DecTable[Value];
GoEnd:
  if minus then
    Result := Result + '-';
  While j >= 0 do
  begin
    Result := Result + _Res[j];
    dec(j);
  end;
end;

выставляю лицензию ZLib на код. )))

проверяйте. )))

Добавлено спустя 8 минут 32 секунды:
Re: Конвертация Int64 с разделителем групп разрядов: неужели?!)
походу бесполезный код... я его почти с первого раза и практически без ошибок написал...

Добавлено спустя 2 минуты 39 секунд:
Re: Конвертация Int64 с разделителем групп разрядов: неужели?!)
Ну и, возможно быстрее было бы сразу в строку копировать данные. Надо это или нет?
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение RRYTY » 08.02.2023 14:50:08

Почему не засунуть в Format extended, а не int64?
RRYTY
постоялец
 
Сообщения: 187
Зарегистрирован: 25.12.2021 10:00:32

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение Alex2013 » 08.02.2023 15:06:00

Win32
IntToStrTSv1: 1500
1 334 191 824

IntToStrTSv2: 422
1 334 191 824

IntToStrTSvMove: 1484
1 334 191 824

Мой результат это кстати более свежий экспонат моего "музея электроники " ноут с "Рязанью номер 5"
Win64 (Оптимизация Q1 ) чуть странно но признаю логично .
IntToStrTSv1: 813
1 162 231 173 562 193 651

IntToStrTSv2: 578
1 162 231 173 562 193 651

IntToStrTSvMove: 922
1 162 231 173 562 193 651


Win64 (Оптимизация Q4 )
IntToStrTSv1: 750
3 862 143 513 940 107 882

IntToStrTSv2: 422
3 862 143 513 940 107 882

IntToStrTSvMove: 844
3 862 143 513 940 107 882
Последний раз редактировалось Alex2013 08.02.2023 15:36:13, всего редактировалось 3 раз(а).
Alex2013
долгожитель
 
Сообщения: 2937
Зарегистрирован: 03.04.2013 11:59:44

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение Seenkao » 08.02.2023 15:17:16

моя функция самая худшая. )))

Добавлено спустя 35 минут 29 секунд:
Re: Конвертация Int64 с разделителем групп разрядов: неужели?!)
но если поменять кодировку страницы на cp1251 и произвести микрооптимизации то тут уже моя функция начинает "немного тащить" (до лидера не добрался).
Так что, моя функция зависима от кодировки. :roll:
Код: Выделить всё
const
  DecTable: array[0..9] of Char = ('0','1','2','3','4','5','6','7','8','9');
function IntToStrNew(Value: Int64): string;
var
  _Res: array[0..26] of Char;
  i, j, n: int64;
  minus: boolean = false;
label
  GoEnd;
begin
  if Value = 0 then
  begin
    Result := '0';
    exit;
  end;
  {$push}
  {$Q-}{$R-}
  Result := '';
  n := 0;
  j := 0;
  if Value < 0 then
  begin
    minus := true;
    Value := abs(Value + 1);
  end;
  // тут надо сделать шаг, если значение было минусовое
  if minus then
  begin
    i := Value mod 10 + 1;
    Value := Value div 10;
    if i > 9 then
    begin
      inc(Value);
      _Res[j] := '0';
    end
    else
      _Res[j] := DecTable[i];
    if Value = 0 then
      goto GoEnd;
    inc(j);
    inc(n);
  end;
  while Value > 9 do
  begin
    i := Value mod 10;
    Value := Value div 10;
    _Res[j] := DecTable[i];
    inc(j);
    inc(n);
    if n = 3 then
    begin
      _Res[j] := ' ';
      inc(j);
      n := 0;
    end;
  end;
  _Res[j] := DecTable[Value];
GoEnd:
  if minus then
  begin
    SetLength(Result, j + 2);
    Result[1] := '-';
  end
  else
    SetLength(Result, j + 1);
  n := j;
  While j >= 0 do
  begin
    Result[n - j + 1] := _Res[j];
    dec(j);
  end;
{  if minus then
    Result := Result + '-';
  While j >= 0 do
  begin
    Result := Result + _Res[j];
    dec(j);
  end;      }
  {$pop}
end;
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение iskander » 08.02.2023 16:44:03

Кстати, насчёт Str(), Asmа и иже с ними:
Код: Выделить всё
program test_str;

{$mode objfpc}{$H+}

uses
  SysUtils;

function GetStrLen(AValue: UInt64): Integer; inline;
begin
  case AValue of
    0..9: Result := 1;
    10..99: Result := 2;
    100..999: Result := 3;
    1000..9999: Result := 4;
    10000..99999: Result := 5;
    100000..999999: Result := 6;
    1000000..9999999: Result := 7;
    10000000..99999999: Result := 8;
    100000000..999999999: Result := 9;
    1000000000..9999999999: Result := 10;
    10000000000..99999999999: Result := 11;
    100000000000..999999999999: Result := 12;
    1000000000000..9999999999999: Result := 13;
    10000000000000..99999999999999: Result := 14;
    100000000000000..999999999999999: Result := 15;
    1000000000000000..9999999999999999: Result := 16;
    10000000000000000..99999999999999999: Result := 17;
    100000000000000000..999999999999999999: Result := 18;
    1000000000000000000..9999999999999999999: Result := 19;
  else
    Result := 20;
  end;
end;

type
  TChar2 = array[0..1] of Char;
  PChar2 = ^TChar2;

const
  Mod100Table: array[0..99] of TChar2 = (
    '00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
    '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');

function Str2(AValue: UInt64): string;
var
  Q: UInt64;
  p: PChar2;
begin
  SetLength(Result, GetStrLen(AValue));
  p := @Result[Length(Result)-1];
  while AValue > 99 do begin
    Q := AValue div 100;
    p^ := Mod100Table[AValue - Q * 100];
    AValue := Q;
    Dec(p);
  end;
  if Odd(Length(Result)) then
    PChar(Result)^ := Mod100Table[AValue][1]
  else
    PChar2(Result)^ := Mod100Table[AValue];
end;

var
  a: array of UInt64;

procedure TestStr;
var
  I: Integer;
  s: string;
  Start: UInt64;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    Str(a[I], s);
  WriteLn('Str:  ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

procedure TestStr2;
var
  I: Integer;
  s: string;
  Start: UInt64;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    s := Str2(a[I]);
  WriteLn('Str2: ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

const
  NumCount = 5000000;

var
  I: Integer;

begin
  Randomize;

  SetLength(a, NumCount);
  for I := 0 to High(a) do
    a[I] := Random(High(Int64));

  TestStr;
  TestStr2;

  ReadLn;
end.

Результаты:
Код: Выделить всё
Str:  296
8309892320858202196

Str2: 156
8309892320858202196
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: Конвертация Int64 с разделителем групп разрядов: неужели

Сообщение avmaksimov » 08.02.2023 21:51:09

iskander писал(а):Кстати, насчёт Str(), Asmа и иже с ними:
Код: Выделить всё
program test_str;

{$mode objfpc}{$H+}

uses
  SysUtils;

function GetStrLen(AValue: UInt64): Integer; inline;
begin
  case AValue of
    0..9: Result := 1;
    10..99: Result := 2;
    100..999: Result := 3;
    1000..9999: Result := 4;
    10000..99999: Result := 5;
    100000..999999: Result := 6;
    1000000..9999999: Result := 7;
    10000000..99999999: Result := 8;
    100000000..999999999: Result := 9;
    1000000000..9999999999: Result := 10;
    10000000000..99999999999: Result := 11;
    100000000000..999999999999: Result := 12;
    1000000000000..9999999999999: Result := 13;
    10000000000000..99999999999999: Result := 14;
    100000000000000..999999999999999: Result := 15;
    1000000000000000..9999999999999999: Result := 16;
    10000000000000000..99999999999999999: Result := 17;
    100000000000000000..999999999999999999: Result := 18;
    1000000000000000000..9999999999999999999: Result := 19;
  else
    Result := 20;
  end;
end;

type
  TChar2 = array[0..1] of Char;
  PChar2 = ^TChar2;

const
  Mod100Table: array[0..99] of TChar2 = (
    '00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
    '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');

function Str2(AValue: UInt64): string;
var
  Q: UInt64;
  p: PChar2;
begin
  SetLength(Result, GetStrLen(AValue));
  p := @Result[Length(Result)-1];
  while AValue > 99 do begin
    Q := AValue div 100;
    p^ := Mod100Table[AValue - Q * 100];
    AValue := Q;
    Dec(p);
  end;
  if Odd(Length(Result)) then
    PChar(Result)^ := Mod100Table[AValue][1]
  else
    PChar2(Result)^ := Mod100Table[AValue];
end;

var
  a: array of UInt64;

procedure TestStr;
var
  I: Integer;
  s: string;
  Start: UInt64;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    Str(a[I], s);
  WriteLn('Str:  ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

procedure TestStr2;
var
  I: Integer;
  s: string;
  Start: UInt64;
begin
  Start := GetTickCount64;
  for I := 0 to High(a) do
    s := Str2(a[I]);
  WriteLn('Str2: ', GetTickCount64 - Start);
  WriteLn(s);
  WriteLn;
end;

const
  NumCount = 5000000;

var
  I: Integer;

begin
  Randomize;

  SetLength(a, NumCount);
  for I := 0 to High(a) do
    a[I] := Random(High(Int64));

  TestStr;
  TestStr2;

  ReadLn;
end.

Результаты:
Код: Выделить всё
Str:  296
8309892320858202196

Str2: 156
8309892320858202196

А почему вы используете массивы, а не используете код символа?) Так точно быстрее?
avmaksimov
новенький
 
Сообщения: 21
Зарегистрирован: 17.10.2010 12:38:54

Пред.След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 17

Рейтинг@Mail.ru