mirror of
https://github.com/dlang/phobos.git
synced 2025-05-09 13:02:30 +03:00
Merge pull request #4327 from tsbockman/isPowerOf2
Add `std.math.isPowerOf2()`. Supports floating-point and integers.
This commit is contained in:
commit
7172eda466
8 changed files with 131 additions and 46 deletions
|
@ -4632,7 +4632,8 @@ if (isForwardRange!R && !isRandomAccessRange!R)
|
|||
private auto sumPairwiseN(size_t N, bool needEmptyChecks, F, R)(ref R r)
|
||||
if (isForwardRange!R && !isRandomAccessRange!R)
|
||||
{
|
||||
static assert(!(N & (N-1))); //isPow2
|
||||
import std.math : isPowerOf2;
|
||||
static assert(isPowerOf2(N));
|
||||
static if (N == 2) return sumPair!(needEmptyChecks, F)(r);
|
||||
else return sumPairwiseN!(N/2, needEmptyChecks, F)(r)
|
||||
+ sumPairwiseN!(N/2, needEmptyChecks, F)(r);
|
||||
|
|
|
@ -22,6 +22,7 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
|
|||
import std.conv, std.experimental.allocator.common, std.traits;
|
||||
import std.algorithm : min;
|
||||
import std.typecons : Ternary;
|
||||
import std.math : isPowerOf2;
|
||||
|
||||
static assert(
|
||||
!stateSize!Prefix || Allocator.alignment >= Prefix.alignof,
|
||||
|
|
|
@ -305,6 +305,7 @@ struct BitmappedBlock(size_t theBlockSize, uint theAlignment = platformAlignment
|
|||
*/
|
||||
void[] alignedAllocate(size_t n, uint a)
|
||||
{
|
||||
import std.math : isPowerOf2;
|
||||
assert(a.isPowerOf2);
|
||||
if (a <= alignment) return allocate(n);
|
||||
|
||||
|
|
|
@ -164,6 +164,7 @@ struct Region(ParentAllocator = NullAllocator,
|
|||
*/
|
||||
void[] alignedAllocate(size_t n, uint a)
|
||||
{
|
||||
import std.math : isPowerOf2;
|
||||
assert(a.isPowerOf2);
|
||||
static if (growDownwards)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ Authors: $(HTTP erdani.com, Andrei Alexandrescu), Timon Gehr (`Ternary`)
|
|||
*/
|
||||
module std.experimental.allocator.common;
|
||||
import std.algorithm, std.traits;
|
||||
import std.math : isPowerOf2;
|
||||
|
||||
/**
|
||||
Returns the size in bytes of the state that needs to be allocated to hold an
|
||||
|
@ -307,33 +308,6 @@ package void* alignUpTo(void* ptr, uint alignment)
|
|||
return slack ? ptr + alignment - slack : ptr;
|
||||
}
|
||||
|
||||
// Credit: Matthias Bentrup
|
||||
/**
|
||||
Returns `true` if `x` is a nonzero power of two.
|
||||
*/
|
||||
@safe @nogc nothrow pure
|
||||
package bool isPowerOf2(uint x)
|
||||
{
|
||||
return (x & -x) > (x - 1);
|
||||
}
|
||||
|
||||
@safe @nogc nothrow pure
|
||||
unittest
|
||||
{
|
||||
assert(!isPowerOf2(0));
|
||||
assert(isPowerOf2(1));
|
||||
assert(isPowerOf2(2));
|
||||
assert(!isPowerOf2(3));
|
||||
assert(isPowerOf2(4));
|
||||
assert(!isPowerOf2(5));
|
||||
assert(!isPowerOf2(6));
|
||||
assert(!isPowerOf2(7));
|
||||
assert(isPowerOf2(8));
|
||||
assert(!isPowerOf2(9));
|
||||
assert(!isPowerOf2(10));
|
||||
assert(isPowerOf2(1UL << 31));
|
||||
}
|
||||
|
||||
@safe @nogc nothrow pure
|
||||
package bool isGoodStaticAlignment(uint x)
|
||||
{
|
||||
|
|
115
std/math.d
115
std/math.d
|
@ -47,7 +47,7 @@ $(TR $(TDNW Floating-point operations) $(TD
|
|||
$(TR $(TDNW Introspection) $(TD
|
||||
$(MYREF isFinite) $(MYREF isIdentical) $(MYREF isInfinity) $(MYREF isNaN)
|
||||
$(MYREF isNormal) $(MYREF isSubnormal) $(MYREF signbit) $(MYREF sgn)
|
||||
$(MYREF copysign)
|
||||
$(MYREF copysign) $(MYREF isPowerOf2)
|
||||
))
|
||||
$(TR $(TDNW Complex Numbers) $(TD
|
||||
$(MYREF abs) $(MYREF conj) $(MYREF sin) $(MYREF cos) $(MYREF expi)
|
||||
|
@ -7619,3 +7619,116 @@ T truncPow2(T)(const T val) if (isFloatingPoint!T)
|
|||
assert(truncPow2(T.init).isNaN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether a number is an integer power of two.
|
||||
|
||||
Note that only positive numbers can be integer powers of two. This
|
||||
function always return `false` if `x` is negative or zero.
|
||||
|
||||
Params:
|
||||
x = the number to test
|
||||
|
||||
Returns:
|
||||
`true` if `x` is an integer power of two.
|
||||
*/
|
||||
bool isPowerOf2(X)(const X x) pure @safe nothrow @nogc
|
||||
if (isNumeric!X)
|
||||
{
|
||||
static if (isFloatingPoint!X)
|
||||
{
|
||||
int exp;
|
||||
const X sig = frexp(x, exp);
|
||||
|
||||
return (exp != int.min) && (sig is cast(X)0.5L);
|
||||
}
|
||||
else
|
||||
{
|
||||
static if (isSigned!X)
|
||||
alias W = typeof(x + 0);
|
||||
else
|
||||
alias W = typeof(x + 0u); // For ubyte and ushort W should be uint
|
||||
|
||||
static if (is(X == W))
|
||||
{
|
||||
static if (isSigned!X)
|
||||
return ((x & -x) == x) && (x > -x);
|
||||
else
|
||||
return (x & -x) > (x - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pragma(inline, true);
|
||||
return isPowerOf2(cast(W)x);
|
||||
}
|
||||
}
|
||||
}
|
||||
///
|
||||
unittest
|
||||
{
|
||||
assert( isPowerOf2(1.0L));
|
||||
assert( isPowerOf2(2.0L));
|
||||
assert( isPowerOf2(0.5L));
|
||||
assert( isPowerOf2(pow(2.0L, 96)));
|
||||
assert( isPowerOf2(pow(2.0L, -77)));
|
||||
|
||||
assert(!isPowerOf2(-2.0L));
|
||||
assert(!isPowerOf2(-0.5L));
|
||||
assert(!isPowerOf2(0.0L));
|
||||
assert(!isPowerOf2(4.315));
|
||||
assert(!isPowerOf2(1.0L / 3.0L));
|
||||
|
||||
assert(!isPowerOf2(real.nan));
|
||||
assert(!isPowerOf2(real.infinity));
|
||||
}
|
||||
///
|
||||
unittest
|
||||
{
|
||||
assert( isPowerOf2(1));
|
||||
assert( isPowerOf2(2));
|
||||
assert( isPowerOf2(1uL << 63));
|
||||
|
||||
assert(!isPowerOf2(-4));
|
||||
assert(!isPowerOf2(0));
|
||||
assert(!isPowerOf2(1337u));
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
import std.meta : AliasSeq;
|
||||
|
||||
immutable smallP2 = pow(2.0L, -62);
|
||||
immutable bigP2 = pow(2.0L, 50);
|
||||
immutable smallP7 = pow(7.0L, -35);
|
||||
immutable bigP7 = pow(7.0L, 30);
|
||||
|
||||
foreach (X; AliasSeq!(float, double, real))
|
||||
{
|
||||
immutable min_sub = X.min_normal * X.epsilon;
|
||||
|
||||
foreach (x; AliasSeq!(smallP2, min_sub, X.min_normal, .25L, 0.5L, 1.0L, 2.0L, 8.0L, pow(2.0L, X.max_exp - 1), bigP2))
|
||||
{
|
||||
assert( isPowerOf2(cast(X) x));
|
||||
assert(!isPowerOf2(cast(X)-x));
|
||||
}
|
||||
|
||||
foreach (x; AliasSeq!(0.0L, 3 * min_sub, smallP7, 0.1L, 1337.0L, bigP7, X.max, real.nan, real.infinity))
|
||||
{
|
||||
assert(!isPowerOf2(cast(X) x));
|
||||
assert(!isPowerOf2(cast(X)-x));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (X; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
|
||||
{
|
||||
foreach (x; [1, 2, 4, 8, (X.max >>> 1) + 1])
|
||||
{
|
||||
assert( isPowerOf2(cast(X) x));
|
||||
static if (isSigned!X)
|
||||
assert(!isPowerOf2(cast(X)-x));
|
||||
}
|
||||
|
||||
foreach (x; [0, 3, 5, 13, 77, X.min, X.max])
|
||||
assert(!isPowerOf2(cast(X)x));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2630,7 +2630,7 @@ private:
|
|||
in
|
||||
{
|
||||
assert(range.length >= 4);
|
||||
assert(isPowerOfTwo(range.length));
|
||||
assert(isPowerOf2(range.length));
|
||||
}
|
||||
body
|
||||
{
|
||||
|
@ -2664,7 +2664,7 @@ private:
|
|||
in
|
||||
{
|
||||
assert(range.length >= 4);
|
||||
assert(isPowerOfTwo(range.length));
|
||||
assert(isPowerOf2(range.length));
|
||||
}
|
||||
body
|
||||
{
|
||||
|
@ -2772,7 +2772,7 @@ private:
|
|||
void butterfly(R)(R buf) const
|
||||
in
|
||||
{
|
||||
assert(isPowerOfTwo(buf.length));
|
||||
assert(isPowerOf2(buf.length));
|
||||
}
|
||||
body
|
||||
{
|
||||
|
@ -2859,7 +2859,7 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
enforce(isPowerOfTwo(size),
|
||||
enforce(isPowerOf2(size),
|
||||
"Can only do FFTs on ranges with a size that is a power of two.");
|
||||
auto table = new lookup_t[][bsf(size) + 1];
|
||||
|
||||
|
@ -3287,13 +3287,6 @@ void slowFourier4(Ret, R)(R range, Ret buf)
|
|||
buf[3] = range[0] + range[1] * C(0, 1) - range[2] - range[3] * C(0, 1);
|
||||
}
|
||||
|
||||
bool isPowerOfTwo(N)(N num)
|
||||
if (isScalarType!N && !isFloatingPoint!N)
|
||||
{
|
||||
import core.bitop : bsf, bsr;
|
||||
return bsr(num) == bsf(num);
|
||||
}
|
||||
|
||||
N roundDownToPowerOf2(N)(N num)
|
||||
if (isScalarType!N && !isFloatingPoint!N)
|
||||
{
|
||||
|
|
13
std/uni.d
13
std/uni.d
|
@ -1105,7 +1105,7 @@ template PackedPtr(T)
|
|||
@trusted struct PackedPtrImpl(T, size_t bits)
|
||||
{
|
||||
pure nothrow:
|
||||
static assert(isPowerOf2(bits));
|
||||
static assert(isPow2OrZero(bits));
|
||||
|
||||
this(inout(size_t)* ptr)inout @safe @nogc
|
||||
{
|
||||
|
@ -1503,7 +1503,7 @@ string genUnrolledSwitchSearch(size_t size)
|
|||
import core.bitop : bsr;
|
||||
import std.array : replace;
|
||||
import std.conv : to;
|
||||
assert(isPowerOf2(size));
|
||||
assert(isPow2OrZero(size));
|
||||
string code = `
|
||||
import core.bitop : bsr;
|
||||
auto power = bsr(m)+1;
|
||||
|
@ -1533,15 +1533,16 @@ string genUnrolledSwitchSearch(size_t size)
|
|||
return code;
|
||||
}
|
||||
|
||||
bool isPowerOf2(size_t sz) @safe pure nothrow @nogc
|
||||
bool isPow2OrZero(size_t sz) @safe pure nothrow @nogc
|
||||
{
|
||||
// See also: std.math.isPowerOf2()
|
||||
return (sz & (sz-1)) == 0;
|
||||
}
|
||||
|
||||
size_t uniformLowerBound(alias pred, Range, T)(Range range, T needle)
|
||||
if (is(T : ElementType!Range))
|
||||
{
|
||||
assert(isPowerOf2(range.length));
|
||||
assert(isPow2OrZero(range.length));
|
||||
size_t idx = 0, m = range.length/2;
|
||||
while (m != 0)
|
||||
{
|
||||
|
@ -1557,7 +1558,7 @@ size_t uniformLowerBound(alias pred, Range, T)(Range range, T needle)
|
|||
size_t switchUniformLowerBound(alias pred, Range, T)(Range range, T needle)
|
||||
if (is(T : ElementType!Range))
|
||||
{
|
||||
assert(isPowerOf2(range.length));
|
||||
assert(isPow2OrZero(range.length));
|
||||
size_t idx = 0, m = range.length/2;
|
||||
enum max = 1<<10;
|
||||
while (m >= max)
|
||||
|
@ -1580,7 +1581,7 @@ template sharMethod(alias uniLowerBound)
|
|||
alias pred = binaryFun!_pred;
|
||||
if (range.length == 0)
|
||||
return 0;
|
||||
if (isPowerOf2(range.length))
|
||||
if (isPow2OrZero(range.length))
|
||||
return uniLowerBound!pred(range, needle);
|
||||
size_t n = truncPow2(range.length);
|
||||
if (pred(range[n-1], needle))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue