On Tuesday, 20 May 2014 at 13:03:59 UTC, Nordlöw wrote:
You have a typo: @save instead of @safe
Oops. This happens all the time :-/

You should also guard the use of asm to x86 architectures only with version.
Uh?
I thought the D assembler should be generic? So if the target platform provides some similar mnemonic, I could use the same? But ok. It's just the do-it-yourself overflow protection is so awfully slow (especially for multiplication).

I have also a protection for exponentiation, and that works without asm.
On the other side it requires some helper functions:

/// returns the absolute value of x in the fitting unsigned type
/// (doesn't fail for T.min)
Unsigned!T abs(T)(T x) pure @safe @nogc if(isIntegral!T)
{
   return (x < 0) ? -x : x;
}

/// returns the number of the highest set bit +1 in the given value
/// or 0 if no bit is set
ubyte bitlen(ubyte c) pure @safe @nogc
{
   return (c>15) ? (c>63) ? (c>127) ? 8 : 7
                          :  (c>31) ? 6 : 5
                 :  (c>3) ?   (c>7) ? 4 : 3
                          :   (c>1) ? 2 : c;
// of course lookup table would be better but I'm to lazy to create one
}

/// calculate the maximal power of x 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(ulong x) pure @safe @nogc
{
   assert(x>1); // no useful maxpower exists for 0 and 1
static immutable ubyte[10] mp = [ 127, 80, 63, 55, 49, 45, 43, 40, 38, 37 ]; return (x<139) ? ((x<31) ? ((x<20) ? ((x<16) ? ((x<12) ? mp[x-2] : 47-x) : ((x<18) ? 31 : 30)) : ((x<24) ? ((x<22) ? 29 : 28) : ((x<27) ? 27 : 26))) : ((x<57) ? ((x<41) ? ((x<35) ? 25 : 24) : ((x<48) ? 23 : 22)) : ((x<85) ? ((x<69) ? 21 : 20) : ((x<107) ? 19 : 18)))) : ((x<7132) ? ((x<566) ? ((x<256) ? ((x<185) ? 17 : 16) : ((x<371) ? 15 : 14)) : ((x<1626) ? ((x<921) ? 13 : 12) : ((x<3184) ? 11 : 10))) : ((x<2642246) ? ((x<65536) ? ((x<19113) ? 9 : 8) : ((x<319558) ? 7 : 6)) : ((x<4294967296) ? ((x<50859009) ? 5 : 4) : ((x<6981463658332) ? 3 : 2))));
}

/// full exponentiation without overflow
/// return T.max(for unsigned) or T.min (for signed) if overflow would occur.
T savePow(T)(T base, ubyte exp) pure @safe @nogc 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, so do nothing
      static if(T.sizeof > ulong.sizeof)
      {
         if(base > ulong.max) return T.max;
      }
      if(exp > (maxpow(base)>>(5-bitlen(T.sizeof)))) return T.max;
      return base ^^ exp;
   }
   else
   {
      auto r = savePow(abs!T(base), exp);
      if(r > T.max) return T.min;
      return ((base < 0) && (exp&1)) ? -cast(T)r : cast(T)r;
   }
}

Reply via email to