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