Skip to content

Commit 8212ad2

Browse files
committed
Merge branch 'feature/20-add-ieee-pown-functions' into develop
Fixes #20
2 parents b5026e9 + 0f2d7df commit 8212ad2

File tree

6 files changed

+241
-0
lines changed

6 files changed

+241
-0
lines changed

collection/633.dat

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
function PowN(const X: Extended; const N: Integer): Extended;
2+
var
3+
I: Integer;
4+
begin
5+
if N = 0 then
6+
// IEEE: pown(x, 0) is 1, even when X is zero
7+
Exit(1.0);
8+
if Math.SameValue(1.0, X) then
9+
Exit(1.0);
10+
if Math.IsZero(X) then
11+
begin
12+
if N < 0 then
13+
raise SysUtils.EDivByZero.Create('PowN: Negative exponent for X = 0');
14+
Exit(0.0);
15+
end;
16+
Result := 1.0;
17+
for I := 1 to System.Abs(N) do
18+
Result := Result * X;
19+
if N < 0 then
20+
Result := 1 / Result;
21+
end;

collection/634.dat

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
function PowNZN(const X: Integer; const N: Cardinal): Int64;
2+
var
3+
I: Integer;
4+
begin
5+
if (X = 0) and (N > 0) then
6+
Exit(0);
7+
if X = 1 then
8+
Exit(1);
9+
Result := 1;
10+
for I := 1 to N do
11+
Result := Result * X;
12+
end;

collection/635.dat

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function PowNZZ(const X: Integer; const N: Integer): Extended;
2+
var
3+
I: Integer;
4+
ResultInt: Int64;
5+
begin
6+
if N = 0 then
7+
Exit(1.0);
8+
if X = 1 then
9+
Exit(1.0);
10+
if X = 0 then
11+
begin
12+
if N < 0 then
13+
raise SysUtils.EDivByZero.Create('PowNZZ: Negative exponent for X = 0');
14+
Exit(0.0);
15+
end;
16+
ResultInt := 1;
17+
for I := 1 to System.Abs(N) do
18+
ResultInt := ResultInt * X;
19+
if N > 0 then
20+
Result := ResultInt
21+
else // N < 0
22+
Result := 1 / ResultInt;
23+
end;

collection/maths.ini

+39
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,7 @@ FPC=Y
11781178

11791179
[Pow]
11801180
DescEx="<p>Raises integer value <var>Base</var> to non-negative integer power <var>Exponent</var> and returns the result.</p>"
1181+
SeeAlso=PowN,PowNZN,PowNZZ
11811182
Snip=561.dat
11821183
Delphi2=N
11831184
Delphi3=N
@@ -1197,6 +1198,44 @@ DelphiXE4=Y
11971198
Delphi10S=Y
11981199
FPC=Y
11991200

1201+
[PowN]
1202+
DescEx="<p>IEEE compliant function that raises real number <var>X</var> to the power <var>N</var>.</p>"
1203+
Extra="<p>See IEEE standard 754-2008 for Floating-Point Arithmetic, page 44.</p>"
1204+
Units=SysUtils,Math
1205+
SeeAlso=Pow,PowNZN,PowNZZ
1206+
TestInfo=advanced
1207+
AdvancedTest.Level=unit-tests
1208+
AdvancedTest.URL="https://github.com/delphidabbler/code-snippets/tree/master/tests/Cat-Maths"
1209+
Snip=633.dat
1210+
DelphiXE=Y
1211+
Delphi11A=Y
1212+
Delphi12A=Y
1213+
1214+
[PowNZN]
1215+
DescEx="<p>Raises integer <var>X</var> to non-negative integer power <var>N</var>.</p>"
1216+
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>"
1217+
SeeAlso=Pow,PowN,PowNZZ
1218+
TestInfo=advanced
1219+
AdvancedTest.Level=unit-tests
1220+
AdvancedTest.URL="https://github.com/delphidabbler/code-snippets/tree/master/tests/Cat-Maths"
1221+
Snip=634.dat
1222+
DelphiXE=Y
1223+
Delphi11A=Y
1224+
Delphi12A=Y
1225+
1226+
[PowNZZ]
1227+
DescEx="<p>Raises integer <var>X</var> to integer power <var>N</var>.</p>"
1228+
Extra="<p>Returns an <var>Extended</var> value since the result is not an integer when power <var>N</var> is negative.</p><p>Based on IEEE standard 754-2008 for Floating-Point Arithmetic, page 44, but which restricts <var>X</var> to an integer.</p>"
1229+
Units=SysUtils,
1230+
SeeAlso=Pow,PowN,PowNZN
1231+
TestInfo=advanced
1232+
AdvancedTest.Level=unit-tests
1233+
AdvancedTest.URL="https://github.com/delphidabbler/code-snippets/tree/master/tests/Cat-Maths"
1234+
Snip=635.dat
1235+
DelphiXE=Y
1236+
Delphi11A=Y
1237+
Delphi12A=Y
1238+
12001239
[ResizeRect_A]
12011240
DisplayName="ResizeRect (TSize overload)"
12021241
DescEx="<p>Resizes rectangle <var>R</var> to size <var>NewSize</var>, leaving the top-left position unchanged.</p><p>Returns the resized rectangle.</p>"

tests/Cat-Maths/TestUMathsCatSnippets.pas

+75
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ TestMathsCatSnippets = class(TTestCase)
4040
procedure TestMaxOfArray_Single;
4141
procedure TestMaxOfArray_Double;
4242
procedure TestMaxOfArray_Extended;
43+
procedure TestPowNZN;
44+
procedure TestPowNZZ;
45+
procedure TestPowN;
4346
end;
4447

4548
implementation
@@ -530,6 +533,78 @@ procedure TestMathsCatSnippets.TestMinOfArray_Single;
530533
Check(SameValue(N, MinOfArray(A)), 'Test 5');
531534
end;
532535

536+
procedure TestMathsCatSnippets.TestPowN;
537+
begin
538+
CheckEquals(0, PowN(0, 2), 'PowN(0,2)');
539+
CheckEquals(1, PowN(42, 0), 'PowN(42,0)');
540+
CheckEquals(1, PowN(0, 0), 'PowN(0,0)');
541+
CheckEquals(1, PowN(1, 1), 'PowN(1,1)');
542+
CheckEquals(-1, PowN(-1, 1), 'PowN(-1,1)');
543+
CheckEquals(1, PowN(1, 5), 'PowN(1,5)');
544+
CheckEquals(4, PowN(2, 2), 'PowN(2,2)');
545+
CheckEquals(4, PowN(-2, 2), 'PowN(-2,2)');
546+
CheckEquals(100, PowN(10, 2), 'PowN(10,2)');
547+
CheckEquals(10000, PowN(10, 4), 'PowN(10,2)');
548+
CheckEquals(1.0, PowN(0, 0), 'PowN(0, 0)');
549+
CheckEquals(1/2, PowN(2, -1), 'PowN(2, -1)');
550+
CheckEquals(1/1000, PowN(10, -3), 'PowN(10, -3)');
551+
CheckEquals(-1000, PowN(-10, 3), 'PowN(-10, 3)');
552+
CheckEquals(-1/1000, PowN(-10, -3), 'PowN(-10, -3)');
553+
CheckEquals(4, PowN(2, 2), 'PowN(2,2)');
554+
CheckEquals(4, PowN(-2, 2), 'PowN(-2,2)');
555+
CheckEquals(1/27, PowN(3, -3), 'PowN(3, -3)');
556+
CheckEquals(1/3, PowN(3, -1), 'PowN(3, -1)');
557+
CheckEquals(-1, PowN(-1, -3), 'PowN(-1, -3)');
558+
CheckEquals(4294967296, PowN(2, 32), 'PowN(2, 32');
559+
// Floats
560+
CheckEquals(Math.Power(45.3672, 3.0), PowN(45.3672, 3), 'PowN(45.3672, 12)');
561+
CheckEquals(Math.Power(-0.87659, -7), PowN(-0.87659, -7), 'PowN(-0.87659, -7)');
562+
CheckEquals(Math.Power(45.3672, -3.0), PowN(45.3672, -3), 'PowN(45.3672, -3)');
563+
CheckEquals(Math.Power(-0.87659, -7), PowN(-0.87659, -7), 'PowN(-0.87659, -7)');
564+
CheckEquals(Math.Power(-0.87659, 3), PowN(-0.87659, 3), 'PowN(-0.87659, 3)');
565+
end;
566+
567+
procedure TestMathsCatSnippets.TestPowNZN;
568+
begin
569+
CheckEquals(0, PowNZN(0, 2), 'PowNZN(0,2)');
570+
CheckEquals(1, PowNZN(42, 0), 'PowNZN(42,0)');
571+
CheckEquals(1, PowNZN(0, 0), 'PowNZN(0,0)');
572+
CheckEquals(1, PowNZN(1, 1), 'PowNZN(1,1)');
573+
CheckEquals(-1, PowNZN(-1, 1), 'PowNZN(-1,1)');
574+
CheckEquals(1, PowNZN(1, 5), 'PowNZN(1,5)');
575+
CheckEquals(4, PowNZN(2, 2), 'PowNZN(2,2)');
576+
CheckEquals(4, PowNZN(-2, 2), 'PowNZN(-2,2)');
577+
CheckEquals(100, PowNZN(10, 2), 'PowNZN(10,2)');
578+
CheckEquals(10000, PowNZN(10, 4), 'PowNZN(10,2)');
579+
CheckEquals(-1000, PowNZN(-10, 3), 'PowNZN(-10,3)');
580+
CheckEquals(10000, PowNZN(-10, 4), 'PowNZN(-10,4)');
581+
end;
582+
583+
procedure TestMathsCatSnippets.TestPowNZZ;
584+
begin
585+
CheckEquals(0, PowNZZ(0, 2), 'PowNZZ(0,2)');
586+
CheckEquals(1, PowNZZ(42, 0), 'PowNZZ(42,0)');
587+
CheckEquals(1, PowNZZ(0, 0), 'PowNZZ(0,0)');
588+
CheckEquals(1, PowNZZ(1, 1), 'PowNZZ(1,1)');
589+
CheckEquals(-1, PowNZZ(-1, 1), 'PowNZZ(-1,1)');
590+
CheckEquals(1, PowNZZ(1, 5), 'PowNZZ(1,5)');
591+
CheckEquals(4, PowNZZ(2, 2), 'PowNZZ(2,2)');
592+
CheckEquals(4, PowNZZ(-2, 2), 'PowNZZ(-2,2)');
593+
CheckEquals(100, PowNZZ(10, 2), 'PowNZZ(10,2)');
594+
CheckEquals(10000, PowNZZ(10, 4), 'PowNZZ(10,2)');
595+
CheckEquals(1.0, PowNZZ(0, 0), 'PowNZZ(0, 0)');
596+
CheckEquals(1/2, PowNZZ(2, -1), 'PowNZZ(2, -1)');
597+
CheckEquals(1/1000, PowNZZ(10, -3), 'PowNZZ(10, -3)');
598+
CheckEquals(-1000, PowNZZ(-10, 3), 'PowNZZ(-10, 3)');
599+
CheckEquals(-1/1000, PowNZZ(-10, -3), 'PowNZZ(-10, -3)');
600+
CheckEquals(4, PowNZZ(2, 2), 'PowNZZ(2,2)');
601+
CheckEquals(4, PowNZZ(-2, 2), 'PowNZZ(-2,2)');
602+
CheckEquals(1/27, PowNZZ(3, -3), 'PowNZZ(3, -3)');
603+
CheckEquals(1/3, PowNZZ(3, -1), 'PowNZZ(3, -1)');
604+
CheckEquals(-1, PowNZZ(-1, -3), 'PowNZZ(-1, -3)');
605+
CheckEquals(4294967296, PowNZZ(2, 32), 'PowNZZ(2, 32');
606+
end;
607+
533608
procedure TestMathsCatSnippets.TestResizeRect_A;
534609
var
535610
R: Types.TRect;

tests/Cat-Maths/UMathsCatSnippets.pas

+71
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,15 @@ function Pow(const Base: Int64; const Exponent: Byte): Int64;
219219
{Raises integer value Base to non-negative integer power Exponent and returns
220220
the result.}
221221

222+
function PowN(const X: Extended; const N: Integer): Extended;
223+
{IEEE compliant function that raises real number X to the power N.}
224+
225+
function PowNZZ(const X: Integer; const N: Integer): Extended;
226+
{Raises integer X to non-negative integer power N.}
227+
228+
function PowNZN(const X: Integer; const N: Cardinal): Int64;
229+
{Raises integer X to integer power N.}
230+
222231
function RectArea(const R: Windows.TRect): Int64;
223232
{Returns the area of the given rectangle.}
224233

@@ -1026,6 +1035,68 @@ function Pow(const Base: Int64; const Exponent: Byte): Int64;
10261035
Result := Result * Base;
10271036
end;
10281037

1038+
function PowN(const X: Extended; const N: Integer): Extended;
1039+
{IEEE compliant function that raises real number X to the power N.}
1040+
var
1041+
I: Integer;
1042+
begin
1043+
if N = 0 then
1044+
// IEEE: pown(x, 0) is 1, even when X is zero
1045+
Exit(1.0);
1046+
if Math.SameValue(1.0, X) then
1047+
Exit(1.0);
1048+
if Math.IsZero(X) then
1049+
begin
1050+
if N < 0 then
1051+
raise SysUtils.EDivByZero.Create('PowN: Negative exponent for X = 0');
1052+
Exit(0.0);
1053+
end;
1054+
Result := 1.0;
1055+
for I := 1 to System.Abs(N) do
1056+
Result := Result * X;
1057+
if N < 0 then
1058+
Result := 1 / Result;
1059+
end;
1060+
1061+
function PowNZN(const X: Integer; const N: Cardinal): Int64;
1062+
{Raises integer X to integer power N.}
1063+
var
1064+
I: Integer;
1065+
begin
1066+
if (X = 0) and (N > 0) then
1067+
Exit(0);
1068+
if X = 1 then
1069+
Exit(1);
1070+
Result := 1;
1071+
for I := 1 to N do
1072+
Result := Result * X;
1073+
end;
1074+
1075+
function PowNZZ(const X: Integer; const N: Integer): Extended;
1076+
{Raises integer X to non-negative integer power N.}
1077+
var
1078+
I: Integer;
1079+
ResultInt: Int64;
1080+
begin
1081+
if N = 0 then
1082+
Exit(1.0);
1083+
if X = 1 then
1084+
Exit(1.0);
1085+
if X = 0 then
1086+
begin
1087+
if N < 0 then
1088+
raise SysUtils.EDivByZero.Create('PowNZZ: Negative exponent for X = 0');
1089+
Exit(0.0);
1090+
end;
1091+
ResultInt := 1;
1092+
for I := 1 to System.Abs(N) do
1093+
ResultInt := ResultInt * X;
1094+
if N > 0 then
1095+
Result := ResultInt
1096+
else // N < 0
1097+
Result := 1 / ResultInt;
1098+
end;
1099+
10291100
function RectArea(const R: Windows.TRect): Int64;
10301101
{Returns the area of the given rectangle.}
10311102
begin

0 commit comments

Comments
 (0)