Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fb53ba7

Browse files
Merge branch 'feature/39-add-digitpowersum-routine' into develop
Fixes #39
2 parents cfadac8 + 6b31fb0 commit fb53ba7

File tree

5 files changed

+163
-11
lines changed

5 files changed

+163
-11
lines changed

‎collection/634.dat‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
function PowNZN(const X: Integer; const N: Cardinal): Int64;
22
var
33
I: Integer;
4+
OverflowGuard: Int64;
45
begin
5-
if (X = 0) and (N > 0) then
6-
Exit(0);
7-
if X = 1 then
6+
if N = 0 then
7+
// IEEE: pown(x, 0) is 1, even when X is zero
88
Exit(1);
9+
if X = 0 then
10+
// pown(0, n) = 0, for all positive n
11+
Exit(0);
12+
OverflowGuard := High(Int64) div Abs(X);
913
Result := 1;
1014
for I := 1 to N do
15+
begin
16+
if OverflowGuard < Abs(Result) then
17+
raise SysUtils.EOverflow.CreateFmt(
18+
'Overflow calculating %d to the power %d', [X, N]
19+
);
1120
Result := Result * X;
21+
end;
1222
end;

‎collection/661.dat‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
function DigitPowerSum(N: Integer; const Base: Byte; const Exponent: Byte):
2+
Int64;
3+
var
4+
SignOfN: Math.TValueSign;
5+
Digit: Integer;
6+
PowerDigit: Int64;
7+
begin
8+
if Base < 2 then
9+
raise SysUtils.EArgumentException.Create(
10+
'Base must be in the range 2..255'
11+
);
12+
if N = 0 then
13+
Exit(0);
14+
SignOfN := Math.Sign(N);
15+
N := Abs(N);
16+
Result := 0;
17+
repeat
18+
Digit := N mod Base;
19+
PowerDigit := PowNZN(Digit, Exponent);
20+
if High(Int64) - PowerDigit < Abs(Result) then
21+
raise SysUtils.EOverflow.Create('Overflow calculating digit power sum');
22+
Result := Result + PowerDigit;
23+
N := N div Base;
24+
until N = 0;
25+
if SignOfN = Math.NegativeValue then
26+
Result := -1 * Result;
27+
end;

‎collection/maths.ini‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ Extra="<p>Sums of digits of negative numbers are negative, for example <mono>Dig
620620
TestInfo=advanced
621621
AdvancedTest.Level=unit-tests
622622
AdvancedTest.URL="https://github.com/delphidabbler/code-snippets/tree/master/tests/Cat-Maths"
623-
SeeAlso=DigitSumBase
623+
SeeAlso=DigitSumBase,DigitPowerSum
624624
Snip=418.dat
625625
Delphi2=N
626626
Delphi3=N
@@ -1391,8 +1391,9 @@ Delphi11A=Y
13911391
Delphi12A=Y
13921392

13931393
[PowNZN]
1394-
DescEx="<p>Raises integer <var>X</var> to non-negative integer power <var>N</var>.</p>"
1394+
DescEx="<p>Raises integer <var>X</var> to non-negative integer power <var>N</var>.</p><p>If the result is too large to be represented as an <var>Int64</var> value then an <var>EOverflow</var> exception is raised.</p>"
13951395
Extra="<p>Returns an <var>integer</var> value because the power <var>N</var> is non-negative which guarantees that the result is integral.</p><p>Based on IEEE standard 754-2008 for Floating-Point Arithmetic, page 44, but which restricts <var>X</var> to an integer and <var>N</var> to a non-negative integer.</p>"
1396+
Units=SysUtils
13961397
SeeAlso=Pow,PowN,PowNZZ
13971398
TestInfo=advanced
13981399
AdvancedTest.Level=unit-tests
@@ -1762,7 +1763,7 @@ DisplayName="DigitSumBase"
17621763
DescEx="<p>Calculates the sum of all the digits of integer <var>N</var> when epxressed in base <var>Base</var>. The returned value has the same sign as <var>N</var>.</p><p>Bases up to 255 are supported. If <var>Base</var> &lt; 2 then an <var>EArgumentException</var> exception is raised.</p>"
17631764
Kind=routine
17641765
Units=SysUtils,Math
1765-
SeeAlso=DigitSum
1766+
SeeAlso=DigitSum,DigitPowerSum
17661767
TestInfo=advanced
17671768
AdvancedTest.Level=unit-tests
17681769
AdvancedTest.URL="https://github.com/delphidabbler/code-snippets/tree/master/tests/Cat-Maths"
@@ -1797,3 +1798,17 @@ AdvancedTest.URL="https://github.com/delphidabbler/code-snippets/tree/master/tes
17971798
Snip=659.dat
17981799
DelphiXE=Y
17991800
Delphi12A=Y
1801+
1802+
[DigitPowerSum]
1803+
DisplayName=DigitPowerSum
1804+
DescEx="<p>Calculates the sum of all the digits of integer <var>N</var> in base <var>Base</var> where each digit is raised to the power <var>Exponent</var>. The returned value has the same sign as <var>N</var>.</p><p>If the result is too large to be represented as an <var>Int64</var> value then an <var>EOverflow</var> exception is raised.</p><p>Bases up to 255 are supported. If <var>Base</var> &lt;= 2 then an <var>EArgumentException</var> exception is raised.</p>"
1805+
Kind=routine
1806+
Units=SysUtils,Math
1807+
Depends=PowNZN
1808+
SeeAlso=DigitSum,DigitSumBase
1809+
TestInfo=advanced
1810+
AdvancedTest.Level=unit-tests
1811+
AdvancedTest.URL="https://github.com/delphidabbler/code-snippets/tree/master/tests/Cat-Maths"
1812+
Snip=661.dat
1813+
DelphiXE=Y
1814+
Delphi12A=Y

‎tests/Cat-Maths/TestUMathsCatSnippets.pas‎

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ TestMathsCatSnippets = class(TTestCase)
2020
procedure TestWeightedArithMean_Double_Except4;
2121
procedure TestDigitSumBase_Except;
2222
procedure TestDigitsOf_ArgExcept;
23+
procedure TestPowNZN_EOverflow;
24+
procedure TestDigitPowerSum_EOverflow;
25+
procedure TestDigitPowerSum_EArgumentException;
2326
function EqualArrays(const Left, Right: TBytes): Boolean;
2427
function ReverseArray(const A: TBytes): TBytes;
2528
published
@@ -51,7 +54,7 @@ TestMathsCatSnippets = class(TTestCase)
5154
procedure TestMaxOfArray_Single;
5255
procedure TestMaxOfArray_Double;
5356
procedure TestMaxOfArray_Extended;
54-
procedure TestPowNZN;
57+
procedure TestPowNZN;// required by DigitPowerSum
5558
procedure TestPowNZZ;
5659
procedure TestPowN;
5760
procedure TestArraySum_Single;
@@ -77,6 +80,7 @@ TestMathsCatSnippets = class(TTestCase)
7780
procedure TestDigitCountBase;
7881
procedure TestDigitSumBase;
7982
procedure TestDigitsOf;
83+
procedure TestDigitPowerSum;
8084
end;
8185

8286
implementation
@@ -416,6 +420,33 @@ procedure TestMathsCatSnippets.TestDigitCountR;
416420
CheckEquals(5, DigitCountR(-12345), 'DigitCountR(-12345)');
417421
end;
418422

423+
procedure TestMathsCatSnippets.TestDigitPowerSum;
424+
begin
425+
CheckEquals(35, DigitPowerSum(135, 10, 2), '#1');
426+
CheckEquals(0, DigitPowerSum(0, 8, 5), '#2');
427+
CheckEquals(3, DigitPowerSum(510, 10, 0), '#3');
428+
CheckEquals(30, DigitPowerSum($FF, 16, 1), '#4');
429+
CheckEquals(12613, DigitPowerSum(1685237180, 10, 4), '#5');
430+
CheckEquals(77907, DigitPowerSum(1685237180 {6472ADBC hex}, 16, 4), '#6');
431+
CheckEquals(6740, DigitPowerSum(1685237180 {14434526674 oct}, 8, 4), '#7');
432+
CheckEquals(-6740, DigitPowerSum(-1685237180 {14434526674 oct}, 8, 4), '#8');
433+
CheckEquals(17, DigitPowerSum(1685237180 {1100100011100101010110110111100 bin}, 2, 4), '#9');
434+
CheckEquals(2409140909625644483, DigitPowerSum(MaxInt {C87E66B7 base 15}, 15, 16), '#10');
435+
CheckException(TestDigitPowerSum_EArgumentException, EArgumentException, 'EArgumentException');
436+
CheckException(TestDigitPowerSum_EOverflow, EOverflow, 'EOverflow');
437+
// EOverflow can also be raised by PowNZN, not tested here
438+
end;
439+
440+
procedure TestMathsCatSnippets.TestDigitPowerSum_EArgumentException;
441+
begin
442+
DigitPowerSum(42, 1, 2); // Base = 1 => EArgumentException
443+
end;
444+
445+
procedure TestMathsCatSnippets.TestDigitPowerSum_EOverflow;
446+
begin
447+
DigitPowerSum(88888888, 10, 20); // overflows High(Int64) by 1
448+
end;
449+
419450
procedure TestMathsCatSnippets.TestDigitsOf;
420451
var
421452
E: TBytes;
@@ -930,6 +961,12 @@ procedure TestMathsCatSnippets.TestPowNZN;
930961
CheckEquals(10000, PowNZN(10, 4), 'PowNZN(10,2)');
931962
CheckEquals(-1000, PowNZN(-10, 3), 'PowNZN(-10,3)');
932963
CheckEquals(10000, PowNZN(-10, 4), 'PowNZN(-10,4)');
964+
CheckException(TestPowNZN_EOverflow, EOverflow, 'EOverflow');
965+
end;
966+
967+
procedure TestMathsCatSnippets.TestPowNZN_EOverflow;
968+
begin
969+
PowNZN(2, 63);
933970
end;
934971

935972
procedure TestMathsCatSnippets.TestPowNZZ;

‎tests/Cat-Maths/UMathsCatSnippets.pas‎

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* The unit is copyright © 2005-2024 by Peter Johnson & Contributors and is
77
* licensed under the MIT License (https://opensource.org/licenses/MIT).
88
*
9-
* Generated on : Tue, 07 Jan 2025 13:13:01 GMT.
9+
* Generated on : Thu, 09 Jan 2025 10:55:06 GMT.
1010
* Generated by : DelphiDabbler CodeSnip Release 4.24.0.
1111
*
1212
* The latest version of CodeSnip is available from the CodeSnip GitHub project
@@ -129,6 +129,18 @@ function DigitCountBase(N: Int64; const Base: Byte): Cardinal;
129129
}
130130
function DigitCountR(AValue: Int64): Integer;
131131

132+
{
133+
Calculates the sum of all the digits of integer N in base Base where each
134+
digit is raised to the power Exponent. The returned value has the same sign as
135+
N.
136+
If the result is too large to be represented as an Int64 value then an
137+
EOverflow exception is raised.
138+
Bases up to 255 are supported. If Base <= 2 then an EArgumentException
139+
exception is raised.
140+
}
141+
function DigitPowerSum(N: Integer; const Base: Byte; const Exponent: Byte):
142+
Int64;
143+
132144
{
133145
Returns an array containing the digits of integer N when expressed in base
134146
Base. The array is ordered with the least significant digit first.
@@ -358,6 +370,8 @@ function PowN(const X: Extended; const N: Integer): Extended;
358370

359371
{
360372
Raises integer X to non-negative integer power N.
373+
If the result is too large to be represented as an Int64 value then an
374+
EOverflow exception is raised.
361375
}
362376
function PowNZN(const X: Integer; const N: Cardinal): Int64;
363377

@@ -894,6 +908,43 @@ function DigitCountR(AValue: Int64): Integer;
894908
Result := 1 + DigitCountR(AValue div 10)
895909
end;
896910

911+
{
912+
Calculates the sum of all the digits of integer N in base Base where each
913+
digit is raised to the power Exponent. The returned value has the same sign as
914+
N.
915+
If the result is too large to be represented as an Int64 value then an
916+
EOverflow exception is raised.
917+
Bases up to 255 are supported. If Base <= 2 then an EArgumentException
918+
exception is raised.
919+
}
920+
function DigitPowerSum(N: Integer; const Base: Byte; const Exponent: Byte):
921+
Int64;
922+
var
923+
SignOfN: Math.TValueSign;
924+
Digit: Integer;
925+
PowerDigit: Int64;
926+
begin
927+
if Base < 2 then
928+
raise SysUtils.EArgumentException.Create(
929+
'Base must be in the range 2..255'
930+
);
931+
if N = 0 then
932+
Exit(0);
933+
SignOfN := Math.Sign(N);
934+
N := Abs(N);
935+
Result := 0;
936+
repeat
937+
Digit := N mod Base;
938+
PowerDigit := PowNZN(Digit, Exponent);
939+
if High(Int64) - PowerDigit < Abs(Result) then
940+
raise SysUtils.EOverflow.Create('Overflow calculating digit power sum');
941+
Result := Result + PowerDigit;
942+
N := N div Base;
943+
until N = 0;
944+
if SignOfN = Math.NegativeValue then
945+
Result := -1 * Result;
946+
end;
947+
897948
{
898949
Returns an array containing the digits of integer N when expressed in base
899950
Base. The array is ordered with the least significant digit first.
@@ -1610,18 +1661,30 @@ function PowN(const X: Extended; const N: Integer): Extended;
16101661

16111662
{
16121663
Raises integer X to non-negative integer power N.
1664+
If the result is too large to be represented as an Int64 value then an
1665+
EOverflow exception is raised.
16131666
}
16141667
function PowNZN(const X: Integer; const N: Cardinal): Int64;
16151668
var
16161669
I: Integer;
1670+
OverflowGuard: Int64;
16171671
begin
1618-
if (X = 0) and (N > 0) then
1619-
Exit(0);
1620-
if X = 1 then
1672+
if N = 0 then
1673+
// IEEE: pown(x, 0) is 1, even when X is zero
16211674
Exit(1);
1675+
if X = 0 then
1676+
// pown(0, n) = 0, for all positive n
1677+
Exit(0);
1678+
OverflowGuard := High(Int64) div Abs(X);
16221679
Result := 1;
16231680
for I := 1 to N do
1681+
begin
1682+
if OverflowGuard < Abs(Result) then
1683+
raise SysUtils.EOverflow.CreateFmt(
1684+
'Overflow calculating %d to the power %d', [X, N]
1685+
);
16241686
Result := Result * X;
1687+
end;
16251688
end;
16261689

16271690
{

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /