June 03, 2005
In article <d7o12k$2dv4$1@digitaldaemon.com>, Andrew Fedoniouk says...
>
>Cool!
>
>David, would it be possible to write also toNumeric ?
>
>Like this:
>
>std.boxer.Box  toNumeric(const char[] s, bool bAllowSep = false)
>
>?
>
>Andrew.

Here's a working copy! My first one I stayed up too late working on it and I made a few mistakes...which they're all fixed in this version. The nice thing about this code, is that it uses Phobos' builded in std.boxer and std.conv functions to do its work, which are already within the runtime library. Except of course for the isNumeric() function which can be found at the begnning of this thread.

Well, I hope this does the trick...but it will be kool to see what others will come up with! ;)

# /+
#  ' Source  : toNumeric.d - Convert a string into a boxed numeric
#  ' Version : v0.2 Beta
#  ' Author  : David L. 'SpottedTiger' Davis
#  ' Created : 02.Jun.05: Compiled with dmd v0.125
#  ' Modified: 03.Jun.05: Corrected a number of issues,
#  '         :            and added the complex floats.
#  ' License : Public Domain
#  ' -----------------------------------------------------------
#  ' Note    : When using the std.boxer module, always compile
#  '           with the "-release" dmd commandline switch,
#  '           otherwise you'll get a linker error.
#  ' -----------------------------------------------------------
#  ' To Compile: dmd mycode.d tonumeric.d isnumeric.d -release
#  +/
# private import std.stdio;
# private import std.boxer;
# private import std.string;
# private import std.conv;
# private import isnumeric;
#
# Box toNumeric( in char[] s, in bool bAllowSep = false)
# {
#     Box    boxx;
#     char[] sx        = std.string.strip(s);
#     char[] s1        = "";
#     char[] s2        = "";
#     int    iLen      = s.length;
#     bool   bComplex  = false;
#     bool   bNeg      = false;
#     bool   bExponent = false;
#     bool   bISuffix  = false;
#     bool   bInt      = true;
#     int    j         = 0;
#     char   c;
#     long   l         = 0L;
#     ulong  ul        = 0UL;
#     real   r1        = real.nan;
#     real   r2        = real.nan;
#     //ireal  ir        = ireal.nan;
#     creal  cr        = creal.nan;
#
#     // Check first for NaN and Infinity
#     if (sx == "nan")
#     { boxx = box(float.nan); return boxx; }
#     else if (sx == "inf")
#     { boxx = box(float.infinity); return boxx; }
#     else if (sx == "-inf")
#     { boxx = box(-float.infinity); return boxx; }
#     else if (sx == "nani") // || sx == "0i")
#     { boxx = box(ifloat.nan); return boxx; }
#     else if (sx == "nan+nani" || sx == "nan+0i")
#     { boxx = box(cfloat.re.nan+cfloat.im.nan); return boxx; }
#
#     // If a valid numeric string, set flags before boxing,
#     // else throw an Exception if its not a numeric string.
#     if (isNumeric(sx, bAllowSep))
#     {
#         if (sx[0] == '+')
#             j++;
#
#         // Is a negative number
#         else if (sx[0] == '-')
#         {
#             j++;
#             bNeg = true;
#         }
#
#         for (int i = j; i < s.length; i++)
#         {
#             c = s[i];
#
#             // Decimal found, number is a floating-point
#             if (c == '.')
#                 bInt = false;
#             else if (c == 'e' || c == 'E')
#             {
#                 i++;
#                 // if two exponents found, then
#                 // this is a complex float
#                 if (bExponent)
#                     bComplex = true;
#
#                 bExponent = true;
#                 bInt = false;
#                 continue;
#             }
#             // A single plus-sign found after
#             // the first position, makes this a
#             // complex float.
#             else if (c == '+')
#             {
#                 bComplex = true;
#                 bInt = false;
#             }
#             else if (c == 'i' || c == 'I')
#             {
#                 bISuffix = true;
#                 bInt = false;
#             }
#             //else {}
#         }
#     }
#     else
#     {
#         throw new Exception("Error in toNumeric(in char[], " ~
#                             "in bool = false), the first parameter " ~
#                             s ~ " is not a numeric string!");
#     }
#
#     // Remove Separators that may exist,
#     // if bAllowSep was set to true
#     if (bAllowSep)
#     {
#         sx = std.string.replace(sx, "_", "");
#         sx = std.string.replace(sx, ",", "");
#     }
#
#     // Set to sx's current length
#     iLen = sx.length;
#
#     // Remove suffixes other than 'i' before calling
#     // the conversion functions, else an error with occur.
#     for (int i = sx.length - 2; i < sx.length; i++)
#     {
#         c = sx[i];
#         if (c == 'f' || c == 'F' || c == 'l' ||
#             c == 'L' || c == 'u' || c == 'U' ||
#             c == 'I' || c == 'i')
#             iLen--;
#     }
#
#     //writefln("sx=\"%s\", bNeg=%b, bInt=%b, bISuffix=%b, bComplex=%b",
#     //         sx, bNeg, bInt, bISuffix, bComplex);
#
#     // Adjust sx's length to iLen
#     sx.length = iLen;
#
#     // Positive Whole Number
#     if (bInt && !bNeg)
#     {
#         //writefln("Unsigned Int");
#         ul = std.conv.toUlong(sx);
#         if (ul <= ubyte.max)
#             boxx = box(cast(ubyte)ul);
#         else if (ul <= ushort.max)
#             boxx = box(cast(ushort)ul);
#         else if (ul <= uint.max)
#             boxx = box(cast(uint)ul);
#         else
#             boxx = box(ul);
#     }
#     // Negative Whole Numer
#     else if (bInt && bNeg)
#     {
#         //writefln("Signed Int");
#         l = std.conv.toLong(sx);
#         if (l >= byte.min && l <= byte.max)
#             boxx = box(cast(byte)l);
#         else if (l >= short.min && l <= short.max)
#             boxx = box(cast(short)l);
#         else if (l >= int.min && l <= int.max)
#             boxx = box(cast(int)l);
#         else
#             boxx = box(cast(long)l);
#     }
#     // Regular Floating-Point Number
#     else if (!bISuffix && !bComplex)
#     {
#         //writefln("Regular Float");
#         r1 = std.conv.toReal(sx);
#         if (r1 >= float.min && r1 <= float.max)
#             boxx = box(cast(float)r1);
#         else if (r1 >= double.min && r1 <= double.max)
#             boxx = box(cast(double)r1);
#         else
#             boxx = box(r1);
#     }
#     /*************************************************/
#     /*  ** Walter still working on putting in the ** */
#     /*  ** toIfloat() thru toCfloat() functions.  ** */
#     /*************************************************/
#     // Imaginary Floating-Point Number
#     else if (bISuffix && !bComplex)
#     {
#         //writefln("Imaginary Float");
#
#         //ir = std.conv.toIreal(sx);
#         //if (ir <= ifloat.max)
#         //    boxx = box(cast(ifloat)ir);
#         //else if (ir <= idouble.max)
#         //    boxx = box(cast(idouble)ir);
#         //else
#         //    boxx = box(ir);
#
#         //** A temp fix until the toIreal() is ready in std.conv **
#         r1 = std.conv.toReal(sx);
#         if (r1 >= float.min && r1 <= float.max)
#             boxx = box(cast(ifloat)(r1 * 1.0i));
#         else if (r1 >= double.min && r1 <= double.max)
#             boxx = box(cast(idouble)(r1 * 1.0i));
#         else
#             boxx = box(cast(ireal)(r1 * 1.0i));
#     }
#     // Complex Floating-Point Number
#     else if (bComplex)
#     {
#         //writefln("Complex Float");
#         //cr = std.conv.toCreal(sx);
#         //boxx = box(cr);
#
#         //** A temp fix until the toCreal() is ready in std.conv **
#         splitComplexStrings(sx, s1, s2);
#         //writefln("sx=\"%s\", s1=\"%s\", s2=\"%s\"", sx, s1, s2);
#         r1 = toReal(s1);
#         r2 = toReal(s2);
#         cr = cast(creal)(r1 + (r2 * 1.0i));
#         boxx = box(cr);
#     }
#     else
#     {
#         //writefln("Unknown");
#         throw new Exception("Error in toNumeric(in char[], " ~
#                             "in bool = false), the first parameter " ~
#                             s ~ " is not a numeric string!");
#     }
#
#     return boxx;
# }
#
# void main()
# {
#     Box wx;
#
#     wx = toNumeric("123456");
#     writefln("unbox!(uint)(wx)=%d", unbox!(uint)(wx));
#
#     wx = toNumeric("-124599");
#     writefln("unbox!(long)(wx)=%8d", unbox!(long)(wx));
#
#     wx = toNumeric("1.234");
#     writefln("unbox!(double)(wx)=%8.3f", unbox!(double)(wx));
#
#     wx = toNumeric("1.234fi");
#     writefln("unbox!(ifloat)(wx)=%g", unbox!(ifloat)(wx));
#
#     wx = toNumeric("1.234e+12");
#     writefln("unbox!(float)(wx)=%8.4g", unbox!(float)(wx));
#
#     wx = toNumeric("1.234e+12+345.4e+34i");
#     writefln("unbox!(creal)(wx)=%g", unbox!(creal)(wx));
#
#     wx = toNumeric("nan+nani");
#     writefln("unbox!(creal)(wx)=%g", unbox!(creal)(wx));
# }
#
# /+
#  ' Splits a complex floats (cfloat, cdouble, and creal) into two workable
strings.
#  ' Grammar:
#  ' (for cfloat, cdouble, and creal)
#  ' ['+'|'-']digit(s)[.][digit(s)][[e-|e+]digit(s)][+]
#  '         [digit(s)[.][digit(s)][[e-|e+]digit(s)][i|f|L|Li|fi]]
#  '      or [nan|nani|nan+nani|inf|-inf]
#  '
#  ' creal Range: from 3.362103E-4932+3.362103E-4932i (min)
#  '                to 1.189731E+4932+1.189731E+4932i (max)
#  +/
# bool splitComplexStrings(in char[] s, out char[] s1, out char[] s2)
# {
#     char[] sx   = s;
#     int    iLen = s.length;
#     int    plus = 0;
#
#     s1 = "";
#     s2 = "";
#
#     if (!iLen)
#         throw new Exception("spiitComplexStrings(): input string is an empty
string.");
#
#     if (iLen >= 2)
#     {
#         sx = std.string.tolower(s);
#         // When "nan" or "nani" just return them.
#         if (s == "nan" || s == "nani" || s == "nan+nani")
#         { s1 = "nan"; s2 = "nani"; return 1; }
#
#         if (s == "inf")
#         { s1 = "inf"; s2 = "infi"; return 1; }
#
#         if (s == "-inf")
#         { s1 = "-inf"; s2 = "-infi"; return 1; }
#     }
#
#     // Split the original string out into two strings.
#     for (int i = 1; i < iLen; i++)
#         if ((sx[i - 1] != 'e' && sx[i - 1] != 'E') && sx[i] == '+')
#         {
#             s1 = s[0..i];
#             if (i + 1 < iLen - 1)
#                 s2 = s[i + 1..iLen]; // - 1];
#             else
#                 s2 = "0e+0i";
#
#             break;
#         }
#
#     // Handle the case when there's only a single value
#     // to work with, and set the other string to zero.
#     if (!s1.length)
#     { s1 = sx; s2 = "0e+0i"; }
#
#     //writefln( "getComplexStrings() s=\"%s\", s1=\"%s\", s2=\"%s\", len=%d",
#     //           s, s1, s2, len );
#
#     return true;
# }

Output:
----------
C:\dmd>dmd tonumeric.d isnumeric.d -release C:\dmd\bin\..\..\dm\bin\link.exe tonumeric+isnumeric,,,user32+kernel32/noi;

C:\dmd>tonumeric
unbox!(uint)(wx)=123456
unbox!(long)(wx)= -124599
unbox!(double)(wx)=   1.234
unbox!(ifloat)(wx)=1.234
unbox!(float)(wx)=1.234e+12
unbox!(creal)(wx)=1.234e+12+3.454e+36i
unbox!(creal)(wx)=nan+0i

C:\dmd>

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

June 03, 2005
In article <d7pvni$rsr$1@digitaldaemon.com>, kris says...
>
>First time I read through dtoa.c, I was about half way through and thinking "egad! what the feck?" when up pops a comment in the code saying "Now, here's the difficult stuff" ... I knew, at that point, that I was completely out of my depth.

The best part about this profession is being hired to maintain code like that. Perhaps back when that stuff was actually written the few CPU cycles it saved over a readable design were actually important ;)

Sean


1 2
Next ›   Last »