Open delphidabbler opened 1 year ago
function DigitCountBase(X: Int64; Base: Byte): Cardinal:
begin
Assert(Base > 1);
if X <> 0 then
Result := Math.Floor(Math.LogN(Base, Abs(X))) + 1
else
Result := 1;
end;
DigitSumBase
Source: Wikipedia
function DigitSumBase(X: Int64; Base: Byte): Integer;
begin
Assert(Base > 1);
if X = 0 then
Exit(0);
var SignOfX := Math.Sign(X);
X := Abs(X);
var K := Math.Floor(Math.LogN(X));
Result := 0;
for var I := 0 to K do
begin
var BToPowerI := PowNZN9(Base, I);
var BToPowerIPlusOne := PowNZN9(Base, I + 1);
var D := ((X mod BToPowerIPlusOne) - (X mod BToPowerI)) div BToPowerI;
Result := Result + D;
end;
if SignOfX < 0 then
Result : -1 * Result;
end;
function DigitArray(N: UInt64; Base: TByte): TArray<Byte>;
begin
Assert(Base > 1);
SetLength(Result, DigitCountBase(N, Base));
if N > 0 then
for I := 0 to High(Result) do
begin
var BToPowerI := PowNZN9(Base, I);
var BToPowerIPlusOne := PowNZN9(Base, I + 1);
var Result[I] := ((X mod BToPowerIPlusOne) - (X mod BToPowerI)) div BToPowerI;
end
else
Result[0] := 0;
end;
Alternative DigitSumBase
that should be quicker:
function DigitSumBase(X: Int64; Base: Byte): Integer;
begin
Assert(Base > 1);
if X = 0 then
Exit(0);
var SignOfX := Math.Sign(X);
X := Abs(X);
var K := Math.Floor(Math.LogN(X));
Result := 0;
var BToPowerI := 1; // B to power I when I = 0
for var I := 0 to K do
begin
var BToPowerIPlus1 := Base * BToPowerI;
var D := ((X mod BToPowerIPlus1) - (X mod BToPowerI)) div BToPowerI;
Result := Result + D;
BToPowerI := BToPowerIPlus1;
end;
if SignOfX < 0 then
Result : -1 * Result;
end;
Alternative DigitArray
that should be quicker:
function DigitArray(N: UInt64; Base: TByte): TArray<Byte>;
begin
Assert(Base > 1);
SetLength(Result, DigitCountBase(N, Base));
if N > 0 then
begin
var BToPowerI := 1; // B to power I when I = 0
for I := 0 to High(Result) do
begin
var BToPowerIPlus1 := Base * BToPowerI;
Result[I] := ((X mod BToPowerIPlus1) - (X mod BToPowerI)) div BToPowerI;
BToPowerI := BToPowerIPlus1;
end;
end
else
Result[0] := 0;
end;
Can have overloads of all above functions for UInt64 parameter that are same except don't need to worry about sign.
In fact the above functions could be rewritten to handle sign then call unsigned overload. E.g.:
function DigitSumBase(const X: UInt64; const Base: Byte): Cardinal; overload;
begin
Assert(Base > 1);
if X = 0 then
Exit(0);
var K := Math.Floor(Math.LogN(X)); // digit count - 1
Result := 0;
var BToPowerI := 1; // B to power I when I = 0
for var I := 0 to K do
begin
var BToPowerIPlus1 := Base * BToPowerI;
var D := ((X mod BToPowerIPlus1) - (X mod BToPowerI)) div BToPowerI;
Result := Result + D;
BToPowerI := BToPowerIPlus1;
end;
end;
function DigitSumBase(X: Int64; Base: Byte): Integer; overload;
begin
Assert(Base > 1);
// safe to convert Cardinal to Integer since max possible Result is much lower than MaxInt
Result := Integer(DigitSumBase(UInt64(Abs(X)), Base));
if X < 0 then
Result : -1 * Result;
end;
Version of DigitSumBase
that raises each digit to given natural number power.
function DigitPowerSum(X: UInt64; Base: Byte; Exponent: Cardinal): Cardinal;
begin
Assert(Base > 1);
if X = 0 then
Exit(0);
var K := Math.Floor(Math.LogN(X)); // digit count - 1
Result := 0;
var BToPowerI := 1; // B to power I when I = 0
for var I := 0 to K do
begin
var BToPowerIPlus1 := Base * BToPowerI;
var D := ((X mod BToPowerIPlus1) - (X mod BToPowerI)) div BToPowerI;
Result := Result + PowNZN(D, Exponent);
BToPowerI := BToPowerIPlus1;
end;
end;
function DigitPowerSum(X: Int64; Base: Byte; Exponent: Cardinal): Integer; overload;
begin
Assert(Base > 1);
var UResult :≈ DigitSumBase(UInt64(Abs(X)), Base, Exponent);
if UResult > MaxInt then
raise EOutOfRange('DigitPowerSum: Result exceeds MaxInt');
Result := Integer(UResult);
if X < 0 then
Result : -1 * Result;
end;
If n ∈ ℕ (n ≠ 0) and b is the number base (b>1) then the number of digits, d, of n is