On Tuesday, 8 July 2014 at 06:08:58 UTC, Brian Schott wrote:
On Tuesday, 8 July 2014 at 06:02:51 UTC, Iain Buclaw via Digitalmars-d wrote:
I would ask why are you passing integers to isNaN.

We passed T to isNaN, and sometimes T was uint.

I would like to have a NaN in any type and be able to call isNaN for any (numeric) type. In fact I work with the following:

/// add a property to numeric types that can be used as return value if a result is out of bounds
template @property T invalid(T) @primitive if(isNumeric!T)
{
   static if(isFloat!T)
      return T.init;
   else static if(isSigned!T)
      return T.min;
   else // unsigned
      return T.max;
}

/// returns the save (not invalid) minimum value for the given type
template @property T smin(T) @primitive if(isNumeric!T)
{
   static if(isIntegral!T && isSigned!T)
      return T.min+1;
   else
      return T.min;
}

/// returns the save (not invalid) maximum value for the given type
template @property T smax(T) @primitive if(isNumeric!T)
{
   static if(isUnsigned!T)
      return T.max-1u;
   else
      return T.max;
}

/// take any NaN as invalid floatingpoint value,
/// T.max as invalid value of unsigned types and
/// T.min as invalid value of signed types
bool isInvalid(T)(const(T) x) @primitive if(isNumeric!T)
{
   static if(isFloat!T)
      return isNaN(x);
   else static if(isSigned!T)
      return x == T.min;
   else // unsigned
      return x == T.max;
}

(btw: @primitive is my internal shorthand for "pure @safe @nogc @nothrow")

because it allows to define save functions like e.g. a save downcast:

/// returns T.invalid if x is outside the target type range
T limit(T, U)(const(U) x) @primitive if(isNumeric!T && isNumeric!U)
{
   static if(Unqual!T == Unqual!U) // nop
      return x;
   else static if(isFloat!T)
      return cast(T)x; // let D handle this internally
   else static if(isFloat!U)
return (isNaN(x) || x <= cast(U)T.min-1.0f || x >= cast(U)T.max+1.0f) ? T.invalid : cast(T)x;
   else static if(isSigned!T)
   {
      static if(T.sizeof > U.sizeof) // nothing to limit
         return cast(T)x;
      else static if(isUnsigned!U) // limit one direction
         return (x > T.max) ? T.invalid : cast(T)x;
      else // limit both directions
         return (x < T.min || x > T.max) ? T.invalid : cast(T)x;
   }
   else // unsigned result
   {
      static if(isSigned!U) // prohibit negative values
         if(x < 0) return T.invalid;

      static if(T.sizeof >= U.sizeof) // no further limit
         return cast(T)x;
      else // prohibit also big positive values
         return (x > T.max) ? T.invalid : cast(T)x;
   }
}



Reply via email to