core.checkedint
Dominikus Dittes Scherkl via Digitalmars-d
digitalmars-d at puremagic.com
Fri Jun 24 10:25:32 PDT 2016
On Friday, 24 June 2016 at 16:56:36 UTC, Andrei Alexandrescu
wrote:
> There are a few simple enhancements to add to core.checkedint:
>
> 1. No need for different names (addu/adds) etc., overloading
> should take care of it (simplifies caller code). Right now the
> API is an odd mix of overloading and distinct names.
>
> 2. The overflow flag should be an integral, not a bool, so you
> get to count how many overflows there were. This is minor but
> has no extra cost on the happy case.
>
> 3. There should be an exponentiation function.
>
> So I'm thinking of the signatures:
>
> pure nothrow @nogc @safe
> {
> int add(int x, int y, ref uint overflows);
> uint add(uint x, uint y, ref uint overflows);
> long add(long x, int y, ref uint overflows);
> ulong add(ulong x, uint y, ref uint overflows);
>
> int mul(int x, int y, ref uint overflows);
> uint mul(uint x, uint y, ref uint overflows);
> long mul(long x, int y, ref uint overflows);
> ulong mul(ulong x, uint y, ref uint overflows);
>
> int sub(int x, int y, ref uint overflows);
> uint sub(uint x, uint y, ref uint overflows);
> long sub(long x, int y, ref uint overflows);
> ulong sub(ulong x, uint y, ref uint overflows);
>
> int neg(int x, ref uint overflows);
> long neg(long x, ref uint overflows);
>
> int pow(int x, int y, ref uint overflows);
> uint pow(uint x, uint y, ref uint overflows);
> long pow(long x, int y, ref uint overflows);
> ulong pow(ulong x, uint y, ref uint overflows);
> }
>
> Thoughts?
>
>
> Andrei
I have a save exponentiation function (+ two helper functions
that may also be useful on their own):
/// add a property to numeric types that can be used as return
value if a result is out of bounds
template invalid(T) if(isNumeric!T)
{
static if(isFloatingPoint!T)
@property enum invalid = T.init;
else static if(isSigned!T)
@property enum invalid = T.min; // 0x80..00
else // unsigned
@property enum invalid = T.max; // 0xFF..FF
}
/// calculate the maximal power of the value that would fit in an
ucent
/// for smaller types simply shift down the result
/// (e.g. divide by 4 to calc the maxpower that would fit in an
uint)
ubyte maxpow(const ulong a) pure @safe @nogc nothrow
{
assert(a>1); // no useful maxpower exists for 0 and 1
static immutable ubyte[55] mp = [ 127, 80, 63, 55, 49, 45, 43,
40,
38, 37, 35, 34, 33, 32, 31, 31, 30, 30, 29, 29, 28, 28, 27,
27,
27, 26, 26, 26, 26, 25, 25, 25, 25, 24, 24, 24, 24, 24, 24,
23,
23, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22
];
return (a<139) ? (a<57) ? mp[cast(ubyte)a-2]
: ((a<85) ? ((a<69) ? 21 : 20)
: ((a<107) ? 19 : 18))
: ((a<7132) ? ((a<566) ? ((a<256) ? ((a<185) ? 17 : 16)
: ((a<371) ? 15 : 14))
: ((a<1626) ? ((a<921) ? 13 : 12)
: ((a<3184) ? 11 : 10)))
: ((a<2642246) ? ((a<65536) ? ((a<19113) ? 9 : 8)
: ((a<319558) ? 7 : 6))
: ((a<4294967296) ? ((a<50859009) ? 5 : 4)
: ((a<6981463658332) ? 3 : 2))));
}
/// exponentiation without overflow
/// return invalid if overflow would occur.
T safePow(T)(const(T) base, const ubyte exp) pure @safe @nogc
nothrow if(isIntegral!T)
{
static if(isUnsigned!T)
{
if(!exp) return 1; // x^^0 is always 1
if(exp == 1 || base < 2) return base; // x^^1 = x, 1^^n = 1
and 0^^n = 0, so do nothing
static if(T.sizeof > ulong.sizeof)
{
if(base > ulong.max) return invalid!T;
}
if(exp > (maxpow(base)>>(5-bitlen(T.sizeof)))) return
invalid!T;
return base ^^ exp; // calc only if no overflow for sure
(very efficient)
}
else
{
auto r = safePow(abs(base), exp); // sometimes calc even if
result won't fit
if(r > T.max) return invalid!T; // but at least we can
easily detect if it happened
return (base < 0 && odd(exp)) ? -cast(T)r : cast(T)r;
}
}
unittest
{
void test(T)()
{
T r;
foreach(base; T.min..T.max+1)
{
foreach(exp; 0..256)
{
r = safePow(base, exp);
if(r == invalid!T)
{
assert(base^^exp > T.max, "max wrong:
"+T.stringOf());
break;
}
assert(r == base^^exp, "calc wrong");
}
}
}
test!byte;
test!ubyte;
test!short;
test!ushort;
/+ test!int;
test!uint;
test!long;
test!ulong; +/
}
More information about the Digitalmars-d
mailing list