On Wednesday, 18 July 2018 at 13:12:05 UTC, Ivan Kazmenko wrote:
On Tuesday, 17 July 2018 at 21:18:12 UTC, John Colvin wrote:
Just do what std.typecons.Proxy does and return float.nan for the incomparable case.

Isn't it slow though on current processors? I just threw together a test program.
Leaving x uninitialized, or using floats, work about the same.
No, floats are a whole lot less slow.
But I agree, I would still prefer to have a signed bool which uses only 1 byte and provide _much_ faster comparison to NaN. And I have created one, but as it is not supported by the language natively, it internally has to use
float, so is not faster (or even slower):

/// signed boolean type (2bit), has the values neg (0b11), zero (0b00), pos (0b01) and nan (0b10) /// this is an extended boolean that split "true" into positive/negative and "false" into zero/NaN
struct sbool
{
pure:
@safe:
@nogc:
nothrow:
   enum { neg = 0b11, zero = 0b00, pos = 0b01, nan = 0b10 };

   this(T)(const(T) x) if(isNumeric!T)
   {
      static if(is(Unqual!T == sbool))
         val = x.val; /// pos -> 1, neg -> 3, zero -> 0, nan -> 2
      else static if(is(Unqual!T == bool))
         val = x ? pos : zero;
      else static if(isUnsigned!T)
         val = x.isInvalid ? nan : (x>0) ? pos : zero;
      else // signed or safe signed
val = x.isInvalid ? nan : (x<0) ? neg : (x>0) ? pos : zero;
   }

   T opCast(T)() const if(isNumeric!T)
   {
      static if(is(Unqual!T == sbool))
         return this;
      else static if(is(Unqual!T == bool))
return val&1; // pos and neg are mapped to true, zero and NaN are mapped to false
      else static if(isFloatingPoint!T)
         return tsgn[val];
      else
         return val == nan ? invalid!T : cast(T)tsgn[val];
   }

   sbool opAssign(T)(const(T) x) if(isNumeric!T)
   {
      return this(x);
   }

sbool opOpAssign(string op)(const sbool x) if(op == "+" || op == "-" || op == "*" || op == "/" || op == "%")
   {
static if(op == "+") // attention! pos+neg = neg+pos = nan !!
         val = tadd[val];
else static if(op == "-") // attention! pos-pos = neg-neg = nan !!
         val = tsub[val];
      else static if(op == "*")
         val = tmul[val];
      else static if(op == "/")
         val = tdiv[val];
      else static if(op == "%")
         val = trem[val];
      val >>= x.val<<1;
      val &= 3;
      return this;
   }

   sbool opUnary(string op)() if(op == "++" || op == "--")
   {
      mixin(op~"val");
      val &= 3;
      return this;
   }

sbool opUnary(string op)() const if(op == "+" || op == "-" || op == "~")
   {
      static if(op == "+") return this;
      sbool r = this;
      mixin("r.val = "~op~"r.val");
      r.val &= 3;
      return r;
   }

sbool opBinary(string op)(const(sbool) x) const if(op == "+" || op == "-" || op == "*" || op == "/" || op == "%")
   {
      sbool r = this;
      return mixin("r "~op~"= x");
   }

Signed!T opBinary(string op, T)(const(T) x) const if(isNumeric!T && op == "*")
   {
      static if(isUnsigned!T)
      {
         alias R = Signed!T;
         if(val == nan || x.isInvalid) return invalid!R;
         if(val == zero) return 0;
         if(x > R.max) return invalid!R;
         return (val == pos) ? R(x) : -R(x);
      }
      else // signed or float: return type is same as T
      {
         if(x.isInvalid) return x;
         final switch(val)
         {
         case pos: return x;
         case neg: return -x;
         case zero: return 0;
         case nan: return invalid!T;
         }
      }
   }

Signed!T opBinaryRight(string op, T)(const(T) x) const if(isNumeric!T && op == "*")
   {
      return opBinary!"*"(x);
   }
private:
   ubyte val = nan;

static immutable float[4] tsgn = [ 0.0f, 1.0f, float.init, -1.0f ]; // composition tables 0: -1 N 1 0 1: -1 N 1 0 N: -1 N 1 0 -1: -1 N 1 0 static immutable ubyte[4] tadd = [ 0b_11_10_01_00, 0b_10_10_01_01, 0b_10_10_10_10, 0b_11_10_10_11 ]; static immutable ubyte[4] tsub = [ 0b_01_10_11_00, 0b_01_10_10_01, 0b_10_10_10_10, 0b_10_10_11_11 ]; static immutable ubyte[4] tmul = [ 0b_00_10_00_00, 0b_11_10_01_00, 0b_10_10_10_10, 0b_01_10_11_00 ]; static immutable ubyte[4] tdiv = [ 0b_00_10_00_10, 0b_11_10_01_10, 0b_10_10_10_10, 0b_01_10_11_10 ]; static immutable ubyte[4] trem = [ 0b_00_10_00_10, 0b_01_10_01_10, 0b_10_10_10_10, 0b_11_10_11_10 ];
   // remainder table is designed so, that if you define
   // quot = (abs(a)/abs(b)) * (sbool(a)/sbool(b));
   // rem  = (abs(a)%abs(b)) * (sbool(a)%sbool(b));
// then assert(a == quot*b + rem) holds for all (a,b) with b != 0
}

unittest
{
   byte quot, rem;
   for(byte a = 127; a >= -127; --a)
   {
      for(byte b = 127; b >= -127; --b)
      {
quot = cast(byte)( (abs(a)/abs(b)) * (sbool(a)/sbool(b)) ); rem = cast(byte)( (abs(a)%abs(b)) * (sbool(a)%sbool(b)) ); assert((b == 0 && isInvalid(quot) && isInvalid(rem)) || a == quot*b + rem);
      }
   }
}



Reply via email to