LNS (логарифмический формат чисел)

Любые обсуждения, не нарушающие правил форума.

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

LNS (логарифмический формат чисел)

Сообщение Alexander » 03.08.2025 20:30:10

Читая в Википедии статью про логарифм наткнулся на абзац рассказывающий о логарифмических представлениях чисел. Решил (используя ИИ) посмотреть как они эффективны на обычном ПК (там говорилось, что им нужно специальное "железо", для проявления их эффективности). Результат получился не очень (в 3 раза медленнее чем обычно вместо ускорения), но может быть всё равно какой-то интерес (скорее для расширения кругозора) это может представлять. Тем более в принципе такое "железо" выпускалось реально. Если интересно могу кроме этой начальной версии показать весь диалог с ИИ. А может и можно что-то в нём ускорить и он станет быстрее.

Код: Выделить всё
unit logoptunit;

{
    Logarithmic number system (LNS) unit.
    Version: 1.
    Written on FreePascal (https://freepascal.org/).
    Copyright (C) 2025  Artyomov Alexander
    http://self-made-free.ru/
    aralni@mail.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
}

{$mode objfpc}{$H+}

interface

type
  TLogNumber = record
    LogAbs: Double;    // логарифм модуля
    Sign: ShortInt;    // -1, 0, 1
  end;

function MakeLogNumber(X: Double): TLogNumber;
function LogToFloat(L: TLogNumber): Double;

function LogMul(A, B: TLogNumber): TLogNumber;
function LogDiv(A, B: TLogNumber): TLogNumber;
function LogPow(A: TLogNumber; Exponent: Double): TLogNumber;
function LogSqrt(A: TLogNumber): TLogNumber;

implementation

uses Math, SysUtils;

procedure FatalError(const Msg: String);
begin
  Writeln(StdErr, 'LogOptUnit error: ', Msg);
  Halt(200);
end;

function MakeLogNumber(X: Double): TLogNumber;
begin
  if X = 0.0 then
  begin
    Result.LogAbs := 0.0;
    Result.Sign := 0;
  end
  else
  begin
    Result.LogAbs := Ln(Abs(X));
    Result.Sign := Sign(X);
  end;
end;

function LogToFloat(L: TLogNumber): Double;
begin
  if L.Sign = 0 then
    Result := 0.0
  else
    Result := L.Sign * Exp(L.LogAbs);
end;

function LogMul(A, B: TLogNumber): TLogNumber;
begin
  if (A.Sign = 0) or (B.Sign = 0) then
    Exit(MakeLogNumber(0.0));
  Result.LogAbs := A.LogAbs + B.LogAbs;
  Result.Sign := A.Sign * B.Sign;
end;

function LogDiv(A, B: TLogNumber): TLogNumber;
begin
  if B.Sign = 0 then
    FatalError('Division by zero in LogDiv');
  if A.Sign = 0 then
    Exit(MakeLogNumber(0.0));
  Result.LogAbs := A.LogAbs - B.LogAbs;
  Result.Sign := A.Sign * B.Sign;
end;

function LogPow(A: TLogNumber; Exponent: Double): TLogNumber;
begin
  if A.Sign = 0 then
    Exit(MakeLogNumber(0.0));
  Result.LogAbs := A.LogAbs * Exponent;

  if Frac(Exponent) = 0 then
  begin
    // целая степень
    if Odd(Trunc(Exponent)) then
      Result.Sign := A.Sign
    else
      Result.Sign := 1;
  end
  else
  begin
    if A.Sign < 0 then
      FatalError('Negative number to fractional power in LogPow');
    Result.Sign := 1;
  end;
end;

function LogSqrt(A: TLogNumber): TLogNumber;
begin
  Result := LogPow(A, 0.5);
end;

end.


Код: Выделить всё
program testlogopt;

{
    Logarithmic number system (LNS) unit test.
    Version: 1.
    Written on FreePascal (https://freepascal.org/).
    Copyright (C) 2025  Artyomov Alexander
    http://self-made-free.ru/
    aralni@mail.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
}

uses
  logoptunit;

var
  a, b, c: TLogNumber;

begin
  a := MakeLogNumber(2.0);
  b := MakeLogNumber(8.0);
  c := LogMul(a, b);
  Writeln('2 * 8 = ', LogToFloat(c):0:2);

  c := LogDiv(b, a);
  Writeln('8 / 2 = ', LogToFloat(c):0:2);

  c := LogPow(a, 3);
  Writeln('2 ^ 3 = ', LogToFloat(c):0:2);

  c := LogSqrt(b);
  Writeln('sqrt(8) = ', LogToFloat(c):0:4);
end.


Код: Выделить всё
program test_logopt_speed;
{$MODE OBJFPC}{$H+}

{
    Logarithmic number system (LNS) unit. Speed test.
    Version: 1.
    Written on FreePascal (https://freepascal.org/).
    Copyright (C) 2025  Artyomov Alexander
    http://self-made-free.ru/
    aralni@mail.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
}

uses
  logoptunit, sysutils, math, DateUtils;

const
  N = 1000000;

var
  i: Integer;
  normalA, normalB, normalResult: array of Double;
  logA, logB, logResult: array of TLogNumber;
  tStart, tEnd: TDateTime;
  totalNormal, totalLog: Double;

begin
  Randomize;
  SetLength(normalA, N);
  SetLength(normalB, N);
  SetLength(normalResult, N);
  SetLength(logA, N);
  SetLength(logB, N);
  SetLength(logResult, N);

  // Инициализация массивов
  for i := 0 to N - 1 do
  begin
    normalA[i] := Random * 1000 + 1e-3; // не ноль
    normalB[i] := Random * 1000 + 1e-3;
    logA[i] := MakeLogNumber(normalA[i]);
    logB[i] := MakeLogNumber(normalB[i]);
  end;

  // Обычное умножение
  tStart := Now;
  for i := 0 to N - 1 do
    normalResult[i] := normalA[i] * normalB[i];
  tEnd := Now;
  totalNormal := 0;
  for i := 0 to N - 1 do
    totalNormal += normalResult[i];
  Writeln('Обычное умножение: ', MilliSecondsBetween(tEnd, tStart), ' мс');

  // Логарифмическое умножение
  tStart := Now;
  for i := 0 to N - 1 do
    logResult[i] := LogMul(logA[i], logB[i]);
  tEnd := Now;
  totalLog := 0;
  for i := 0 to N - 1 do
    totalLog += LogToFloat(logResult[i]);
  Writeln('Логарифмическое умножение: ', MilliSecondsBetween(tEnd, tStart), ' мс');

  // Простая проверка (сумма результатов)
  Writeln('Сумма обычных результатов: ', totalNormal:0:4);
  Writeln('Сумма логарифмических результатов: ', totalLog:0:4);
end.


Код: Выделить всё
./test_logopt_speed
Обычное умножение: 10 мс
Логарифмическое умножение: 29 мс
Сумма обычных результатов: 250092748142.3317
Сумма логарифмических результатов: 250092748142.3317
Аватара пользователя
Alexander
энтузиаст
 
Сообщения: 837
Зарегистрирован: 18.12.2005 19:10:00
Откуда: оттуда

Re: LNS (логарифмический формат чисел)

Сообщение Дож » 08.08.2025 00:42:14

1. if в LogMul лишний, его можно просто выкинуть
2. Нужен inline, т.к. функция маленькая
3. Параметры передавать как const
4. Результат писать в out параметр, чтобы не было копирования

Код: Выделить всё
procedure LogMulOut(const A, B: TLogNumber; out Dst: TLogNumber); inline;
begin
  Dst.LogAbs := A.LogAbs + B.LogAbs;
  Dst.Sign := A.Sign * B.Sign;
end;


Основная деградация производительности скорее всего из-за памяти. Double занимает 8 байт, TLogNumber -- 16, из-за этого в два раза больше обращений к памяти требуется. Если поменять тип LogAbs на Single, либо в normal массивы докинуть 8 байт мусора, показатели должны приблизиться друг к другу.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47


Вернуться в Потрепаться

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

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

Рейтинг@Mail.ru
cron