Difference between revisions of "is power of two"

From Lazarus wiki
Jump to navigationJump to search
m (mv statement in right position)
m (Categorised page)
Line 1: Line 1:
 
Checking whether a given number is an integer power of two is a classical demonstration showing how conclusions can be drawn from a number's internal representation.
 
Checking whether a given number is an integer power of two is a classical demonstration showing how conclusions can be drawn from a number's internal representation.
 +
 
<syntaxhighlight lang="pascal" line start="3">
 
<syntaxhighlight lang="pascal" line start="3">
 
uses
 
uses
Line 5: Line 6:
 
math;
 
math;
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
{{Doc|package=RTL|unit=system|identifier=popcnt|text=<syntaxhighlight lang="pascal" enclose="none">system.popCnt</syntaxhighlight>}} counts the number of set bits within an integer.
 
{{Doc|package=RTL|unit=system|identifier=popcnt|text=<syntaxhighlight lang="pascal" enclose="none">system.popCnt</syntaxhighlight>}} counts the number of set bits within an integer.
 
The function's name derives from “population count.”
 
The function's name derives from “population count.”
 
Population count, because [[Set|sets]] are usually implemented by utilizing integers, where a set bit means a certain element is part of a set.
 
Population count, because [[Set|sets]] are usually implemented by utilizing integers, where a set bit means a certain element is part of a set.
 +
 
<syntaxhighlight lang="pascal" enclose="none">popCnt</syntaxhighlight> applied on an integer representing a set will return its cardinality (what the <syntaxhighlight lang="pascal" enclose="none">card</syntaxhighlight> function defined by [[Extended Pascal]] does).
 
<syntaxhighlight lang="pascal" enclose="none">popCnt</syntaxhighlight> applied on an integer representing a set will return its cardinality (what the <syntaxhighlight lang="pascal" enclose="none">card</syntaxhighlight> function defined by [[Extended Pascal]] does).
 +
 
<syntaxhighlight lang="pascal" line start="7">
 
<syntaxhighlight lang="pascal" line start="7">
 
(**
 
(**
Line 22: Line 26:
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
Now, you want to overload your function, since it is not necessarily the case you can limit your calculation to non-negative integers only.
 
Now, you want to overload your function, since it is not necessarily the case you can limit your calculation to non-negative integers only.
 
Ensure you are typecasting the given value, so the compiler chooses the right, our “base” function.
 
Ensure you are typecasting the given value, so the compiler chooses the right, our “base” function.
 +
 
<syntaxhighlight lang="pascal" line start="19">
 
<syntaxhighlight lang="pascal" line start="19">
 
function isPowerOfTwo(const x: int64): longbool;
 
function isPowerOfTwo(const x: int64): longbool;
Line 40: Line 46:
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
Although integer operations are nice, sometimes you have to deal with floating point numbers.
 
Although integer operations are nice, sometimes you have to deal with floating point numbers.
 
Since we wanna know the exponent in the expression <math>2^n = x</math>, and check it is an integer, we can use {{Doc|package=RTL|unit=math|identifier=log2|text=<syntaxhighlight lang="pascal" enclose="none">math.log2</syntaxhighlight>}} in conjunction with {{Doc|package=RTL|unit=system|identifier=frac|text=<syntaxhighlight lang="pascal" enclose="none">system.frac</syntaxhighlight>}}.
 
Since we wanna know the exponent in the expression <math>2^n = x</math>, and check it is an integer, we can use {{Doc|package=RTL|unit=math|identifier=log2|text=<syntaxhighlight lang="pascal" enclose="none">math.log2</syntaxhighlight>}} in conjunction with {{Doc|package=RTL|unit=system|identifier=frac|text=<syntaxhighlight lang="pascal" enclose="none">system.frac</syntaxhighlight>}}.
 +
 
<syntaxhighlight lang="pascal" line start="34">
 
<syntaxhighlight lang="pascal" line start="34">
 
function isPowerOfTwo(const x: float): longbool;
 
function isPowerOfTwo(const x: float): longbool;
Line 58: Line 66:
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
Alternatively one could use the following implementation, utilizing {{Doc|package=RTL|unit=math|identifier=frexp|text=<syntaxhighlight lang="pascal" enclose="none">math.frExp</syntaxhighlight>}}.
 
Alternatively one could use the following implementation, utilizing {{Doc|package=RTL|unit=math|identifier=frexp|text=<syntaxhighlight lang="pascal" enclose="none">math.frExp</syntaxhighlight>}}.
 
It is even neater, since it does not really calculate the logarithm but just [[IEEE 754 formats|extracts the numbers]] (<syntaxhighlight lang="asm" enclose="none">fxtract</syntaxhighlight> instruction on x86 platforms).
 
It is even neater, since it does not really calculate the logarithm but just [[IEEE 754 formats|extracts the numbers]] (<syntaxhighlight lang="asm" enclose="none">fxtract</syntaxhighlight> instruction on x86 platforms).
 
However, (without writing [[Asm|inline assembly]] blocks) one needs to allocate two variables, where only one is actually needed.
 
However, (without writing [[Asm|inline assembly]] blocks) one needs to allocate two variables, where only one is actually needed.
 +
 
<syntaxhighlight lang="pascal" line start="34">
 
<syntaxhighlight lang="pascal" line start="34">
 
function isPowerOfTwo(const x: float): longbool;
 
function isPowerOfTwo(const x: float): longbool;
Line 81: Line 91:
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
[[Category:FPC]]
 
[[Category:Code]]
 
[[Category:Code]]
 +
[[Category:Mathematics]]

Revision as of 03:17, 11 August 2020

Checking whether a given number is an integer power of two is a classical demonstration showing how conclusions can be drawn from a number's internal representation.

3uses
4	// for math.log2
5	math;

system.popCnt counts the number of set bits within an integer. The function's name derives from “population count.” Population count, because sets are usually implemented by utilizing integers, where a set bit means a certain element is part of a set.

popCnt applied on an integer representing a set will return its cardinality (what the card function defined by Extended Pascal does).

 7(**
 8	\brief Determines whether a given number
 9	is an integer power of two.
10	
11	\param x the number to check
12	\return true iff \f$2^n=x\f$ where \f$n \in \mathbb{Z}\f$
13*)
14function isPowerOfTwo(const x: qword): longbool;
15begin
16	isPowerOfTwo := popCnt(x) = 1;
17end;

Now, you want to overload your function, since it is not necessarily the case you can limit your calculation to non-negative integers only. Ensure you are typecasting the given value, so the compiler chooses the right, our “base” function.

19function isPowerOfTwo(const x: int64): longbool;
20begin
21	// a) 2^n is always positive.
22	// b) There is no 2^n that equals zero.
23	if x < 1 then
24	begin
25		isPowerOfTwo := false;
26	end
27	// c) Theoretically you could shortcut for x < 3
28	else
29	begin
30		isPowerOfTwo := isPowerOfTwo(qword(x));
31	end
32end;

Although integer operations are nice, sometimes you have to deal with floating point numbers. Since we wanna know the exponent in the expression [math]\displaystyle{ 2^n = x }[/math], and check it is an integer, we can use math.log2 in conjunction with system.frac.

34function isPowerOfTwo(const x: float): longbool;
35begin
36	{$push}
37	{$boolEval off}
38	if (x <= 0) or isInfinite(x) or isNan(x) then
39	{$pop}
40	begin
41		isPowerOfTwo := false;
42	end
43	else
44	begin
45		isPowerOfTwo := frac(log2(x)) = 0;
46	end;
47end;

Alternatively one could use the following implementation, utilizing math.frExp. It is even neater, since it does not really calculate the logarithm but just extracts the numbers (fxtract instruction on x86 platforms). However, (without writing inline assembly blocks) one needs to allocate two variables, where only one is actually needed.

34function isPowerOfTwo(const x: float): longbool;
35var
36	mantissa: extended;
37	exponent: longint;
38begin
39	{$push}
40	{$boolEval off}
41	if isInfinite(x) or isNan(x) then
42	{$pop}
43	begin
44		isPowerOfTwo := false;
45	end
46	else
47	begin
48		frExp(x, mantissa, exponent);
49		isPowerOfTwo := mantissa = 0.5;
50	end;
51end;