- Код: Выделить всё
- 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




