Thread overview
Sharing InRange.d - (just in case I'm not the only one)
Sep 08, 2005
David L. Davis
Sep 13, 2005
James Dunne
Sep 14, 2005
David L. Davis
[OT] Focusing on isNegative() and BigEndian Compatibility
Sep 19, 2005
David L. Davis
September 08, 2005
Well, I'm beginning to find it a pure headache when I pass different numeric datatyes into general template functions, and trying to compare them against one another. And since I mainly work in Visual Basic v6.0 (in which all numerics types are signed) for a living, I never thought that comparing a long to an ulong, or other signed to unsigned combos would be the slightest problem. Well, I guess I've learned my lesson the hard way, and that's D is a lot like C in this area, maybe it will get better with numeric compares in the future. <g>

Anyway, to pull my fat out of the fire, I've created two templates I'm going to add to my three or four projects that will pretty much fail on negative values (to my surprise!! For sure going forward, I will be adding a lot more unittests against negative values in the future.).

So, I'd like to post them here, just in case someone else might like to use them. And for those who work in a C-like language daliy, this probably isn't even an issue. :P

# /+
#  ' Source     : InRange.d - is value in range.
#  ' Author     : David L. 'SpottedTiger' Davis
#  ' D Compiler : dmd v0.130
#  ' Created    : 08.Sep.05
#  ' Licence    : Public Domain / Contributed to Digital Mars
#  ' --------------------------------------------------------
#  ' To do a unittest: dmd inrange.d -debug=inrange -unittest
#  ' To compile: dmd YourSource.d inrange.d
#  +/
# debug( inrange ) private import std.stdio;
#
# /+
#  ' isNegative!(T)(Tvalue)
#  ' --------------------------------------
#  ' T : the datatype of the input value
#  ' Tvalue : is the value being passed in,
#  '          and compared to see if it is a
#  '          negative number.
#  '
#  ' bool return : returns true if the value
#  '               is a negative number.
#  +/
# template isNegative(T)
# {
#     bool isNegative(in T t)
#     {
#         TypeInfo ti = typeid(T);
#
#         if ((ti is typeid(bit))    ||
#             (ti is typeid(ubyte))  ||
#             (ti is typeid(ushort)) ||
#             (ti is typeid(uint))   ||
#             (ti is typeid(ulong)))
#             return false;
#         else if ((ti is typeid(byte))    ||
#                  (ti is typeid(short))   ||
#                  (ti is typeid(int))     ||
#                  (ti is typeid(long))    ||
#                  (ti is typeid(float))   ||
#                  (ti is typeid(double))  ||
#                  (ti is typeid(real))    ||
#                  (ti is typeid(ifloat))  ||
#                  (ti is typeid(idouble)) ||
#                  (ti is typeid(ireal)))
#         {
#             uint ui = ti.tsize - 1;
#
#             // Code borrowed from the std.math.signbit()
#             ubyte* psign = cast(ubyte*)&t;
#             return (psign[ui] & 0x80) != 0;
#             //^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^
#         }
#         else
#             return false;
#     }
# }
#
# /+
#  ' isValueInRange!(T1, T2)(T1value)
#  ' --------------------------------------
#  ' T1 : the datatype of the input value
#  ' T2 : the base datatype comparing range against
#  ' T1value : is the value being passed in.
#  '
#  ' bool return : returns true if the value is
#  '               within the base datatype's range.
#  '
#  ' Notes :  Compare any Integer value against a
#  ' numeric datatype's min / max, except for the
#  ' floating-point datatypes.
#  +/
# template isValueInRange(T1, T2)
# {
#      bool isValueInRange(in T1 v)
#      {
#          bool bT1neg = isNegative!(T1)(v);
#          bool bT2neg = isNegative!(T2)(T2.min);
#
#          // If same datatype in range of each other.
#          if (typeid(T1) is typeid(T2))
#          {
#              debug( inrange ) writefln("Same datatypes");
#              return true;
#          }
#          // bypassing floats for now, unless they're
#          // the exact same datatype, then the compare
#          // above this one will grab them and returns true.
#          else if (typeid(T1) is typeid(float)   ||
#                   typeid(T1) is typeid(double)  ||
#                   typeid(T1) is typeid(real)    ||
#                   typeid(T1) is typeid(ifloat)  ||
#                   typeid(T1) is typeid(idouble) ||
#                   typeid(T1) is typeid(ireal)   ||
#                   typeid(T1) is typeid(cfloat)  ||
#                   typeid(T1) is typeid(cdouble) ||
#                   typeid(T1) is typeid(creal))
#          {
#              return false;
#          }
#
#          // Negative Value to Positive Base
#          if (bT1neg && !bT2neg)
#          {
#              debug( inrange ) writefln("Negative Value to Positive Base");
#              return false;
#          }
#          // Positive Value to Positive Base
#          else if (((!bT1neg && !bT2neg)))
#          {
#              debug( inrange ) writefln("Positive Value to Positive Base");
#              ulong v2 = cast(ulong)v;
#              ulong ul = cast(ulong)T2.max;
#
#              if (v2 >= 0 && v2 <= ul)
#                  return true;
#              else
#                  return false;
#          }
#          // Positive Value to a Negative Base
#          // (we can ignore below the zero range)
#          else if ((!bT1neg && bT2neg))
#          {
#              debug( inrange ) writefln("Positive Value to a Negative Base");
#              ulong v2 = cast(ulong)v;
#              ulong ul = cast(ulong)T2.max;
#
#              if (v2 >= 0 && v2 <= ul)
#                  return true;
#              else
#                  return false;
#          }
#          // Negative Value to a Negative Base
#          // (we can move both into the positive number range)
#          else if ((bT1neg && bT2neg))
#          {
#              debug( inrange ) writefln("Negative Value to a Negative Base");
#              long l  = cast(long)T2.min;
#              long v2 = cast(long)v;
#              v2 = l - v2;
#
#              if (isNegative!(long)(v2) || v2 == 0)
#                  return true;
#              else
#                  return false;
#          }
#          else
#          {
#             debug( inrange ) writefln("Other");
#             return false;
#          }
#      }
# }
#
# debug( inrange )
# {
# int main()
# {
#     writefln("Unittest done!");
#     return 0;
# }
# }
#
# unittest
# {
#     writefln("Unittest started");
#     ulong ul = 34567890123UL;
#
#     assert(isValueInRange!(int,    ulong)(-123) == false);     // IsNegative
#     assert(isValueInRange!(long,   ulong)(long.min) == false); // IsNegative
#     // Same datatype
#     assert(isValueInRange!(ulong,  ulong)(123UL) == true);
#     // much larger value
#     assert(isValueInRange!(ulong,  uint)(ulong.max) == false); // too large
#     assert(isValueInRange!(ulong,  uint)(ul) == false);
#     assert(isValueInRange!(real,   real)(123.89L) == true);    // Same range
#     assert(isValueInRange!(uint,   long)(456U) == true);       // In range
#     assert(isValueInRange!(uint,   long)(uint.max) == true);   // In range
#     assert(isValueInRange!(ulong,  long)(ulong.max) == false); // too large
#     assert(isValueInRange!(long,   int)(long.min) == false);   // too small
#     assert(isValueInRange!(ulong,  long)(ulong.max) == false); // too large
#     assert(isValueInRange!(int,    long)(int.min) == true);    // In range
#     assert(isValueInRange!(int,    long)(int.max) == true);    // In range
#     assert(isValueInRange!(bit,    long)(true) == true);       // In range
#     assert(isValueInRange!(long,   bit)(2L) == false);         // too large
#     assert(isValueInRange!(long,   bit)(-101L) == false);      // too small
#     assert(isValueInRange!(ushort, byte)(127) == true);        // In range
# }

David L.

-------------------------------------------------------------------
"Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
-------------------------------------------------------------------

MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html
September 13, 2005
Sorry for top-posting, but my comment is buried in the code below...

David L. Davis wrote:
> Well, I'm beginning to find it a pure headache when I pass different numeric
> datatyes into general template functions, and trying to compare them against one
> another. And since I mainly work in Visual Basic v6.0 (in which all numerics
> types are signed) for a living, I never thought that comparing a long to an
> ulong, or other signed to unsigned combos would be the slightest problem. Well,
> I guess I've learned my lesson the hard way, and that's D is a lot like C in
> this area, maybe it will get better with numeric compares in the future. <g>
> 
> Anyway, to pull my fat out of the fire, I've created two templates I'm going to
> add to my three or four projects that will pretty much fail on negative values
> (to my surprise!! For sure going forward, I will be adding a lot more unittests
> against negative values in the future.). 
> 
> So, I'd like to post them here, just in case someone else might like to use
> them. And for those who work in a C-like language daliy, this probably isn't
> even an issue. :P
> 
> # /+
> #  ' Source     : InRange.d - is value in range.
> #  ' Author     : David L. 'SpottedTiger' Davis
> #  ' D Compiler : dmd v0.130
> #  ' Created    : 08.Sep.05
> #  ' Licence    : Public Domain / Contributed to Digital Mars
> #  ' --------------------------------------------------------
> #  ' To do a unittest: dmd inrange.d -debug=inrange -unittest
> #  ' To compile: dmd YourSource.d inrange.d
> #  +/
> # debug( inrange ) private import std.stdio;
> # # /+
> #  ' isNegative!(T)(Tvalue)
> #  ' --------------------------------------
> #  ' T : the datatype of the input value
> #  ' Tvalue : is the value being passed in,
> #  '          and compared to see if it is a
> #  '          negative number.
> #  ' #  ' bool return : returns true if the value  #  '               is a negative number.
> #  +/
> # template isNegative(T)
> # {
> #     bool isNegative(in T t)
> #     {
> #         TypeInfo ti = typeid(T);
> # #         if ((ti is typeid(bit))    || #             (ti is typeid(ubyte))  ||
> #             (ti is typeid(ushort)) ||
> #             (ti is typeid(uint))   ||
> #             (ti is typeid(ulong)))
> #             return false;

This portion is incorrect:

> #         else if ((ti is typeid(byte))    ||
> #                  (ti is typeid(short))   ||
> #                  (ti is typeid(int))     ||
> #                  (ti is typeid(long))    ||
> #                  (ti is typeid(float))   ||
> #                  (ti is typeid(double))  ||
> #                  (ti is typeid(real))    ||
> #                  (ti is typeid(ifloat))  ||
> #                  (ti is typeid(idouble)) ||
> #                  (ti is typeid(ireal)))
> #         {
> #             uint ui = ti.tsize - 1;
> #
> #             // Code borrowed from the std.math.signbit() #             ubyte* psign = cast(ubyte*)&t;
> #             return (psign[ui] & 0x80) != 0;
> #             //^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^
> #         }

The code you 'borrowed' from std.math.signbit is valid only for an IEEE floating point value, not for ints, longs, shorts, etc.  With the integer types (and possibly the floating point types, I'm not sure) there is the endianness issue.

Get someone with a big-endian machine to run your unittests, compiled with GDC.  It should work fine on an X86 arch PC.  However, I can almost guarantee your code will fail on a PPC or Sun box.  I don't have any of those myself, so I can't test.

> #         else
> #             return false;
> #     }
> # }
> # # /+
> #  ' isValueInRange!(T1, T2)(T1value)
> #  ' --------------------------------------
> #  ' T1 : the datatype of the input value
> #  ' T2 : the base datatype comparing range against
> #  ' T1value : is the value being passed in.
> #  ' #  ' bool return : returns true if the value is #  '               within the base datatype's range.
> #  '
> #  ' Notes :  Compare any Integer value against a #  ' numeric datatype's min / max, except for the #  ' floating-point datatypes.
> #  +/
> # template isValueInRange(T1, T2)
> # {
> #      bool isValueInRange(in T1 v)
> #      {
> #          bool bT1neg = isNegative!(T1)(v);
> #          bool bT2neg = isNegative!(T2)(T2.min);
> # #          // If same datatype in range of each other.
> #          if (typeid(T1) is typeid(T2))
> #          {
> #              debug( inrange ) writefln("Same datatypes");
> #              return true;
> #          }
> #          // bypassing floats for now, unless they're
> #          // the exact same datatype, then the compare
> #          // above this one will grab them and returns true.
> #          else if (typeid(T1) is typeid(float)   ||
> #                   typeid(T1) is typeid(double)  ||
> #                   typeid(T1) is typeid(real)    ||
> #                   typeid(T1) is typeid(ifloat)  ||
> #                   typeid(T1) is typeid(idouble) ||
> #                   typeid(T1) is typeid(ireal)   ||
> #                   typeid(T1) is typeid(cfloat)  ||
> #                   typeid(T1) is typeid(cdouble) ||
> #                   typeid(T1) is typeid(creal))
> #          {
> #              return false;
> #          }
> # #          // Negative Value to Positive Base
> #          if (bT1neg && !bT2neg)
> #          {
> #              debug( inrange ) writefln("Negative Value to Positive Base");
> #              return false;
> #          }
> #          // Positive Value to Positive Base
> #          else if (((!bT1neg && !bT2neg)))
> #          {
> #              debug( inrange ) writefln("Positive Value to Positive Base");
> #              ulong v2 = cast(ulong)v;
> #              ulong ul = cast(ulong)T2.max;
> # #              if (v2 >= 0 && v2 <= ul)
> #                  return true;
> #              else
> #                  return false;
> #          }
> #          // Positive Value to a Negative Base
> #          // (we can ignore below the zero range)
> #          else if ((!bT1neg && bT2neg)) #          {
> #              debug( inrange ) writefln("Positive Value to a Negative Base");
> #              ulong v2 = cast(ulong)v;
> #              ulong ul = cast(ulong)T2.max;
> # #              if (v2 >= 0 && v2 <= ul)
> #                  return true;
> #              else
> #                  return false; #          }
> #          // Negative Value to a Negative Base
> #          // (we can move both into the positive number range)
> #          else if ((bT1neg && bT2neg)) #          {
> #              debug( inrange ) writefln("Negative Value to a Negative Base");
> #              long l  = cast(long)T2.min;
> #              long v2 = cast(long)v;
> #              v2 = l - v2;
> # #              if (isNegative!(long)(v2) || v2 == 0)
> #                  return true;
> #              else
> #                  return false;
> #          }
> #          else
> #          {
> #             debug( inrange ) writefln("Other");
> #             return false;
> #          }
> #      }
> # }
> # # debug( inrange )
> # {
> # int main()
> # {
> #     writefln("Unittest done!");
> #     return 0;
> # }
> # }
> # # unittest
> # {
> #     writefln("Unittest started");
> #     ulong ul = 34567890123UL;
> # #     assert(isValueInRange!(int,    ulong)(-123) == false);     // IsNegative
> #     assert(isValueInRange!(long,   ulong)(long.min) == false); // IsNegative
> #     // Same datatype   #     assert(isValueInRange!(ulong,  ulong)(123UL) == true); #     // much larger value
> #     assert(isValueInRange!(ulong,  uint)(ulong.max) == false); // too large
> #     assert(isValueInRange!(ulong,  uint)(ul) == false);        #     assert(isValueInRange!(real,   real)(123.89L) == true);    // Same range
> #     assert(isValueInRange!(uint,   long)(456U) == true);       // In range
> #     assert(isValueInRange!(uint,   long)(uint.max) == true);   // In range
> #     assert(isValueInRange!(ulong,  long)(ulong.max) == false); // too large
> #     assert(isValueInRange!(long,   int)(long.min) == false);   // too small
> #     assert(isValueInRange!(ulong,  long)(ulong.max) == false); // too large
> #     assert(isValueInRange!(int,    long)(int.min) == true);    // In range
> #     assert(isValueInRange!(int,    long)(int.max) == true);    // In range
> #     assert(isValueInRange!(bit,    long)(true) == true);       // In range
> #     assert(isValueInRange!(long,   bit)(2L) == false);         // too large
> #     assert(isValueInRange!(long,   bit)(-101L) == false);      // too small
> #     assert(isValueInRange!(ushort, byte)(127) == true);        // In range
> # }
> 
> David L.
> 
> -------------------------------------------------------------------
> "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
> -------------------------------------------------------------------
> 
> MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html


-- 
Regards,
James Dunne
September 14, 2005
James thanks for your input, my comments are below. ;)

In article <dg5ema$c2a$1@digitaldaemon.com>, James Dunne says...
>
>This portion is incorrect:
>
>> #         else if ((ti is typeid(byte))    ||
>> #                  (ti is typeid(short))   ||
>> #                  (ti is typeid(int))     ||
>> #                  (ti is typeid(long))    ||
>> #                  (ti is typeid(float))   ||
>> #                  (ti is typeid(double))  ||
>> #                  (ti is typeid(real))    ||
>> #                  (ti is typeid(ifloat))  ||
>> #                  (ti is typeid(idouble)) ||
>> #                  (ti is typeid(ireal)))
>> #         {
>> #             uint ui = ti.tsize - 1;
>> #
>> #             // Code borrowed from the std.math.signbit()
>> #             ubyte* psign = cast(ubyte*)&t;
>> #             return (psign[ui] & 0x80) != 0;
>> #             //^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^
>> #         }
>
>The code you 'borrowed' from std.math.signbit is valid only for an IEEE floating point value, not for ints, longs, shorts, etc.  With the integer types (and possibly the floating point types, I'm not sure) there is the endianness issue.

Umm! The negative (which is one bit) is always in the high-ordered byte on the x86 CPU which stores them in a reverse order within memory (I did some assembly in my more youngful days), and it doesn't seem to matter if it's an integer or a float for this 'bit' of information. Below I did some code to show what I mean using the borrowed code from std.math.signbit, showing 'byte' all the way to the 'ireal' datatypes:

# // NegTest.d
# // Intel x86 CPU / WinXP SP2
# private import std.stdio;
#
#     template ShowNegByte(T)
#     {
#     void ShowNegByte(in T v)
#     {
#         TypeInfo ti = typeid(T);
#         uint ui = ti.tsize - 1;
#
#         // Code borrowed from the std.math.signbit()
#         ubyte* psign = cast(ubyte*)&v;
#         writef("type=\"%s\",", ti, " value=", v, " bits=0b");
#
#         for (int i = 0; i < ti.tsize; i++)
#             writef("%08b", cast(ubyte)psign[i]);
#         writef(" sign=%s", ((psign[ui] & 0x80) != 0) ? "true" : "false");
#         writefln();
#         //^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^
#     }
#     }
#
# int main()
# {
#     writef("Intel x86 CPU / WinXP: Checking the "
#            "high-ordered byte for negative: ");
#     ShowNegByte!(byte)(byte.min);
#     ShowNegByte!(byte)(-1);
#     ShowNegByte!(byte)(-127);
#     ShowNegByte!(byte)(1);
#     ShowNegByte!(byte)(byte.max);
#     writefln();
#
#     ShowNegByte!(short)(short.min);
#     ShowNegByte!(short)(-1);
#     ShowNegByte!(short)(-32767);
#     ShowNegByte!(short)(1);
#     ShowNegByte!(short)(short.max);
#     writefln();
#
#     ShowNegByte!(int)(int.min);
#     ShowNegByte!(int)(-1);
#     ShowNegByte!(int)(-64345);
#     ShowNegByte!(int)(1);
#     ShowNegByte!(int)(int.max);
#     writefln();
#
#     ShowNegByte!(long)(long.min);
#     ShowNegByte!(long)(-1);
#     ShowNegByte!(long)(-4546464345);
#     ShowNegByte!(long)(1);
#     ShowNegByte!(long)(long.max);
#     writefln();
#
#     ShowNegByte!(float)(float.min);
#     ShowNegByte!(float)(-1);
#     ShowNegByte!(float)(-32767);
#     ShowNegByte!(float)(1);
#     ShowNegByte!(float)(float.max);
#     writefln();
#
#     ShowNegByte!(double)(double.min);
#     ShowNegByte!(double)(-1);
#     ShowNegByte!(double)(-64345);
#     ShowNegByte!(double)(1);
#     ShowNegByte!(double)(double.max);
#     writefln();
#
#     ShowNegByte!(real)(real.min);
#     ShowNegByte!(real)(-1);
#     ShowNegByte!(real)(-4546464345);
#     ShowNegByte!(real)(1);
#     ShowNegByte!(real)(real.max);
#     writefln();
#
#     ShowNegByte!(ifloat)(ifloat.min);
#     ShowNegByte!(ifloat)(-1i);
#     ShowNegByte!(ifloat)(-32767i);
#     ShowNegByte!(ifloat)(1i);
#     ShowNegByte!(ifloat)(ifloat.max);
#     writefln();
#
#     ShowNegByte!(idouble)(idouble.min);
#     ShowNegByte!(idouble)(-1i);
#     ShowNegByte!(idouble)(-64345i);
#     ShowNegByte!(idouble)(1i);
#     ShowNegByte!(idouble)(idouble.max);
#     writefln();
#
#     ShowNegByte!(ireal)(ireal.min);
#     ShowNegByte!(ireal)(-1i);
#     ShowNegByte!(ireal)(-4546464345i);
#     ShowNegByte!(ireal)(1i);
#     ShowNegByte!(ireal)(ireal.max);
#     writefln();
#     return 0;
# }

<This was the output, but the message would not post with it in!?!>

>Get someone with a big-endian machine to run your unittests, compiled with GDC.  It should work fine on an X86 arch PC.  However, I can almost guarantee your code will fail on a PPC or Sun box.  I don't have any of those myself, so I can't test.
> 
>Regards,
>James Dunne

Yeah, I'm pretty sure you're right that this will only work only on a Intel x86-like CPU...I should've put that into the comments. In fact, I'll start adding a "Source Platform" and a "Target Platform" entrys into my future comments.

Of course, I'd love to know how to setup this code to also run on a big-endian machine and such. So, maybe someone reading this could help me out in this area and show some example code (version statements wrappers that would work), and also run the code on a non-Intel box to test it out.

David L.

-------------------------------------------------------------------
"Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
-------------------------------------------------------------------

MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html
September 19, 2005
In article <dg5ema$c2a$1@digitaldaemon.com>, James Dunne says...
>
> ...
>
>> #         else if ((ti is typeid(byte))    ||
>> #                  (ti is typeid(short))   ||
>> #                  (ti is typeid(int))     ||
>> #                  (ti is typeid(long))    ||
>> #                  (ti is typeid(float))   ||
>> #                  (ti is typeid(double))  ||
>> #                  (ti is typeid(real))    ||
>> #                  (ti is typeid(ifloat))  ||
>> #                  (ti is typeid(idouble)) ||
>> #                  (ti is typeid(ireal)))
>> #         {
>> #             uint ui = ti.tsize - 1;
>> #
>> #             // Code borrowed from the std.math.signbit()
>> #             ubyte* psign = cast(ubyte*)&t;
>> #             return (psign[ui] & 0x80) != 0;
>> #             //^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^
>> #         }
>
>
> ...
>
>Get someone with a big-endian machine to run your unittests, compiled with GDC.  It should work fine on an X86 arch PC.  However, I can almost guarantee your code will fail on a PPC or Sun box.  I don't have any of those myself, so I can't test.
>
> ...
>
>Regards,
>James Dunne

I've looked into what's the different between little-endian (Intel x86 / Windows, Linux) and big-endian (PPC / Mac OS, Linux, Unix) and it appears if I understand it correctly, that only the byte order from the most significant to the least significant are stored in memory the opposite way (but the bits remain in the same order).

If that's so, then shouldn't the simple version statement I've placed in the code below solve this issue?

# /+
#  ' isNegative!(T)(Tvalue)
#  ' --------------------------------------
#  ' T : the datatype of the input value
#  ' [in] v : is the value being passed in,
#  '          and compared to see if it is a
#  '          negative number.
#  '
#  ' bool return : returns true if the value
#  '               is a negative number.
#  '
#  ' Note: That char, wchar, and dchar are unsigned
#  '       according the the D "Basic Data Types"
#  '       descriptions.
#  +/
# template isNegative(T)
# {
#     bool isNegative(in T v)
#     {
#         TypeInfo ti = typeid(T);
#
#         if ((ti is typeid(bit))    ||
#             (ti is typeid(ubyte))  ||
#             (ti is typeid(ushort)) ||
#             (ti is typeid(uint))   ||
#             (ti is typeid(ulong))  ||
#             (ti is typeid(char))   ||
#             (ti is typeid(wchar))  ||
#             (ti is typeid(dchar)))
#             return false;
#         else if ((ti is typeid(byte))    ||
#                  (ti is typeid(short))   ||
#                  (ti is typeid(int))     ||
#                  (ti is typeid(long))    ||
#                  (ti is typeid(float))   ||
#                  (ti is typeid(double))  ||
#                  (ti is typeid(real))    ||
#                  (ti is typeid(ifloat))  ||
#                  (ti is typeid(idouble)) ||
#                  (ti is typeid(ireal)))
#         {
#             // Code borrowed from the std.math.signbit()
#             ubyte* psign = cast(ubyte*)&v;
#
#             // For non-Intel x86 CPUs that use BigEndian byte order
#             version( BigEndian )
#             {
#                 return (psign[0] & 0x80) != 0;
#             }
#             else // defaults to x86's LittleEndian byte order
#             {
#                 uint ui = ti.tsize - 1;
#                 return (psign[ui] & 0x80) != 0;
#             }
#             //^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^
#         }
#         else
#             return false;
#     }
# }

David L.

-------------------------------------------------------------------
"Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
-------------------------------------------------------------------

MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html