digitalmars.D - Requesting a 2nd review: on the floating-point funcs for conv.d
- David L. Davis <SpottedTiger yahoo.com> Apr 16 2005
- "TechnoZeus" <TechnoZeus PeoplePC.com> Apr 21 2005
- pragma <pragma_member pathlink.com> Apr 21 2005
- "TechnoZeus" <TechnoZeus PeoplePC.com> Apr 21 2005
- "Ben Hinkle" <ben.hinkle gmail.com> Apr 22 2005
- "Ben Hinkle" <bhinkle mathworks.com> Apr 22 2005
- David L. Davis <SpottedTiger yahoo.com> Apr 23 2005
Well, I've been pretty busy this past week reworking all of these "from char[]to
floating-point" functions (based on advise gotten from Ben Hinkle) that I'd like
Walter to include into std.conv. With the sol purpose of filling in the gap of
the missing conversion functions for the following datatypes: float, double,
real, ifloat, idouble, ireal, cfloat, cdouble, and creal.
If anyone has any interest at all, please at least use an eye-ball or two to
look over the code, and better yet, if you have the time, copy and paste this
code into dmd v0.121's version of conv.d to test it a bit.
Thanks in advance,
David L.
======================
# //*** Inserted code after //debug=conv within conv.d ***
# private import std.math; // for fabs(), isnan()
# private import std.string; // for atof(), split()
# debug( conv ) private import std.stdio; // for writefln() and printf()
# //*** End of insert ***
#
# //*** Inserted code at the end-of-file of conv.d ***
# /***************************************************************
# * Convert character string to float.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# float toFloat(in char[] s)
# {
# real r;
# float f;
#
# if (!s.length)
# goto Lerr;
#
# r = toReal(s);
# f = cast(float)r;
#
# if (feq(cast(real)f, r) != 1)
# if (toString(f) != toString(r))
# goto Loverflow;
#
# return cast(float)r;
#
# Loverflow:
# conv_overflow(s);
#
# Lerr:
# conv_error(s);
# return 0f;
# }
#
# unittest
# {
# debug( conv ) writefln( "conv.toFloat.unittest" );
# float f;
#
# f = toFloat( "123" );
# assert( f == 123f );
# f = toFloat( "+123" );
# assert( f == +123f );
# f = toFloat( "-123" );
# assert( f == -123f );
# f = toFloat( "123e+2" );
# assert( f == 123e+2f );
#
# f = toFloat( "123e-2" );
# assert( f == 123e-2f );
# f = toFloat( "123." );
# assert( f == 123.f );
# f = toFloat( ".456" );
# assert( f == .456f );
#
# //Min and Max values
# f = toFloat("1.17549e-38");
# assert(feq(cast(real)f, cast(real)1.17549e-38));
# assert(feq(cast(real)f, cast(real)float.min));
# f = toFloat("3.40282e+38");
# assert(toString(f) == toString(3.40282e+38));
#
# //nan
# f = toFloat("nan");
# assert(toString(f) == toString(float.nan));
# }
#
# /***************************************************************
# * Convert character string to double.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# double toDouble(in char[] s)
# {
# real r;
# double d;
#
# if (!s.length)
# goto Lerr;
#
# r = toReal(s);
# d = cast(double)r;
#
# if (feq(r, cast(real)d) != 1)
# if (toString(d) != toString(r))
# goto Loverflow;
#
# return cast(double)r;
#
# Loverflow:
# conv_overflow(s);
#
# Lerr:
# conv_error(s);
# return 0;
# }
#
# unittest
# {
# debug( conv ) writefln( "conv.toDouble.unittest" );
# double d;
#
# d = toDouble( "123" );
# assert( d == 123 );
# d = toDouble( "+123" );
# assert( d == +123 );
# d = toDouble( "-123" );
# assert( d == -123 );
# d = toDouble( "123e2" );
# assert( d == 123e2);
# d = toDouble( "123e-2" );
# assert( d == 123e-2 );
# d = toDouble( "123." );
# assert( d == 123. );
# d = toDouble( ".456" );
# assert( d == .456 );
# d = toDouble( "1.23456E+2" );
# assert( d == 1.23456E+2 );
#
# //Min and Max values
# d = toDouble("2.22507e-308");
# assert(feq(cast(real)d, cast(real)2.22507e-308));
# assert(feq(cast(real)d, cast(real)double.min));
# d = toDouble("1.79769e+308");
# assert(toString(d) == toString(1.79769e+308));
# assert(toString(d) == toString(double.max));
#
# //nan
# d = toDouble("nan");
# assert(toString(d) == toString(double.nan));
# }
#
# /***************************************************************
# * Convert character string to real.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# real toReal(in char[] s)
# {
# char[] sx;
# bit b;
#
# if (!s.length)
# goto Lerr;
#
# b = getFloatStrings(s, sx);
#
# if (b == 0)
# goto Lerr;
#
# return atof(sx);
#
# Lerr:
# conv_error(s);
# return 0.0L;
# }
#
# unittest
# {
# debug(conv) writefln("conv.toReal.unittest");
# real r;
#
# r = toReal("123");
# assert(r == 123L);
# r = toReal("+123");
# assert(r == 123L);
# r = toReal("-123");
# assert(r == -123L);
# r = toReal("123e2");
# assert(feq(r, 123e2L));
# r = toReal("123e-2");
# assert(feq(r, 1.23L));
# r = toReal("123.");
# assert(r == 123L);
# r = toReal(".456");
# assert(r == .456L);
#
# r = toReal("1.23456e+2");
# assert(feq(r, 1.23456e+2L));
# r = toReal(toString(real.max / 2L));
# assert(toString(r) == toString(real.max / 2L));
#
# //Min and Max values
# r = toReal(toString(real.min));
# assert(toString(r) == toString(real.min));
# r = toReal(toString(real.max));
# assert(toString(r) == toString(real.max));
#
# //nan
# r = toReal("nan");
# assert(toString(r) == toString(real.nan));
# }
#
# /***************************************************************
# * Convert character string to ifloat.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# ifloat toIfloat(in char[] s)
# {
# real r;
# ireal ir;
# ifloat ift;
#
# if (!s.length)
# goto Lerr;
#
# r = toReal(s);
# ir = cast(ireal)(r * 1.0i);
# ift = cast(ifloat)(r * 1.0i);
#
# if (feq(ir, cast(ireal)ift) != 1)
# goto Loverflow;
#
# return ift;
#
# Loverflow:
# conv_overflow(s);
#
# Lerr:
# conv_error(s);
# return cast(ifloat)0.0i;
# }
#
# unittest
# {
# debug(conv) writefln("conv.toIfloat.unittest");
# ifloat ift;
#
# ift = toIfloat(toString(ifloat.min));
#
# assert(toString(ift) == toString(ifloat.min) );
# assert(feq(cast(ireal)ift, cast(ireal)ifloat.min));
#
# ift = toIfloat(toString(ifloat.max));
# assert(toString(ift) == toString(ifloat.max));
# assert(feq(cast(ireal)ift, cast(ireal)ifloat.max));
#
# ift = toIfloat(toString(123.45));
# assert(toString(ift) == toString(123.45i));
#
# ift = toIfloat(toString(456.77i));
# assert(toString(ift) == toString(456.77i));
#
# ift = toIfloat(toString(ifloat.nan));
# assert(toString(ift.nan) == toString(ifloat.nan));
# assert(feq(cast(ireal)ift, cast(ireal)ifloat.nan));
# }
#
# /***************************************************************
# * Convert character string to idouble.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# idouble toIdouble(in char[] s)
# {
# real r;
# ireal ir;
# idouble id;
#
# if (!s.length)
# goto Lerr;
#
# r = toReal(s);
# ir = cast(ireal)(r * 1.0i);
# id = cast(idouble)(r * 1.0i);
#
# if (feq(ir, cast(ireal)id) != 1)
# goto Loverflow;
#
# return id;
#
# Loverflow:
# conv_overflow(s);
#
# Lerr:
# conv_error(s);
# return cast(idouble)0.0i;
# }
#
# unittest
# {
# debug(conv) writefln("conv.toIdouble.unittest");
# idouble id;
#
# id = toIdouble(toString(idouble.min));
# assert(toString( id ) == toString(idouble.min));
# assert(feq(cast(ireal)id.re, cast(ireal)idouble.min.re));
# assert(feq(cast(ireal)id.im, cast(ireal)idouble.min.im));
#
# id = toIdouble(toString(idouble.max));
# assert(toString(id) == toString(idouble.max));
# assert(feq(cast(ireal)id.re, cast(ireal)idouble.max.re));
# assert(feq(cast(ireal)id.im, cast(ireal)idouble.max.im));
#
# id = toIdouble(toString("123.45"));
# assert(id == 123.45i);
#
# id = toIdouble(toString(idouble.nan));
# assert(toString(id.nan) == toString(idouble.nan));
# }
#
# /***************************************************************
# * Convert character string to ireal.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# ireal toIreal(in char[] s)
# {
# real r;
# ireal ir;
#
# if (!s.length)
# goto Lerr;
#
# r = toReal(s);
#
# ir = cast(ireal)(r * 1.0i);
#
# return ir;
#
# Lerr:
# conv_error(s);
# return cast(ireal)0.0i;
# }
#
# unittest
# {
# debug(conv) writefln("conv.toIreal.unittest");
# ireal ir;
#
# ir = toIreal(toString(ireal.min));
# assert(toString(ir) == toString(ireal.min));
# assert(feq(cast(real)ir.re, cast(real)ireal.min.re));
# assert(feq(cast(real)ir.im, cast(real)ireal.min.im));
#
# ir = toIreal(toString(ireal.max));
# assert(toString(ir) == toString(ireal.max));
# assert(feq(cast(real)ir.re, cast(real)ireal.max.re));
#
# ir = toIreal(toString("123.45"));
# assert(feq(cast(real)ir.re, cast(real)123.45i));
#
# ir = toIreal(toString(ireal.nan));
# assert(toString(ir.nan) == toString(ireal.nan));
# }
#
# /***************************************************************
# * Convert character string to cfloat.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# cfloat toCfloat(in char[] s)
# {
# char[] s1;
# char[] s2;
# real r1;
# real r2;
# creal cr;
# cfloat cf;
# bit b = 0;
#
# if (!s.length)
# goto Lerr;
#
# b = getFloatStrings(s, s1, s2);
#
# if (b == 0)
# goto Lerr;
#
# r1 = atof(s1);
# r2 = atof(s2);
#
# cr = cast(creal)cast(creal)r1 + cast(creal)(r2 * 1.0i);
# cf = cast(cfloat)r1 + cast(cfloat)(r2 * 1.0i);
#
# if (feq(cr, cast(creal)cf) != 1)
# goto Loverflow;
#
# return cf;
#
# Loverflow:
# conv_overflow(s);
#
# Lerr:
# conv_error(s);
# return cast(cfloat)0.0e-0+0i;
# }
#
# unittest
# {
# debug(conv) writefln("conv.toCfloat.unittest");
# cfloat cf;
#
# cf = toCfloat(toString(cfloat.min));
# assert(toString(cf) == toString(cfloat.min));
#
# cf = toCfloat(toString(cfloat.max));
# assert(toString(cf) == toString(cfloat.max));
#
# cf = toCfloat(toString("1.2345e-5+0i"));
# assert(toString(cf) == toString(1.2345e-5+0i));
# assert(feq(cf, 1.2345e-5+0i));
# }
#
# /***************************************************************
# * Convert character string to cdouble.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# cdouble toCdouble(in char[] s)
# {
# char[] s1;
# char[] s2;
# real r1;
# real r2;
# creal cr;
# cdouble cd;
# bit b = 0;
#
# if (!s.length)
# goto Lerr;
#
# b = getFloatStrings(s, s1, s2);
#
# if (b == 0)
# goto Lerr;
#
# r1 = atof(s1);
# r2 = atof(s2);
#
# cr = cast(creal)cast(creal)r1 + cast(creal)(r2 * 1.0i);
# cd = cast(cdouble)r1 + cast(cdouble)(r2 * 1.0i);
#
# if (feq(cr, cast(creal)cd) != 1)
# goto Loverflow;
#
# return cd;
#
# Loverflow:
# conv_overflow(s);
#
# Lerr:
# conv_error(s);
# return cast(cdouble)0.0e-0+0i;
# }
#
# unittest
# {
# debug(conv) writefln("conv.toCdouble.unittest");
# cdouble cd;
#
# cd = toCdouble(toString(cdouble.min));
# assert(toString(cd) == toString(cdouble.min));
#
# cd = toCdouble(toString(cdouble.max));
# assert(toString( cd ) == toString(cdouble.max));
#
# cd = toCdouble(toString("1.2345e-5+0i"));
# assert(toString( cd ) == toString(1.2345e-5+0i));
# assert(feq(cd, 1.2345e-5+0i));
# }
#
# /***************************************************************
# * Convert character string to creal.
# * Grammar:
# * ['+'|'-'] digit {digit}
# */
# creal toCreal(in char[] s)
# {
# char[] s1;
# char[] s2;
# real r1;
# real r2;
# creal cr;
# bit b = 0;
#
# if (!s.length)
# goto Lerr;
#
# b = getFloatStrings(s, s1, s2);
#
# if (b == 0)
# goto Lerr;
#
# r1 = atof(s1);
# r2 = atof(s2);
#
# if (r2 != 0.0)
# cr = cast(creal)(r1 + (r2 * 1.0i));
# else
# cr = cast(creal)(r1 + cast(creal)0.0i);
#
# return cr;
#
# Lerr:
# conv_error(s);
# return cast(creal)0.0e-0+0i;
# }
#
# unittest
# {
# debug(conv) writefln("conv.toCreal.unittest");
# creal cr;
#
# cr = toCreal(toString(creal.min));
# assert(toString(cr) == toString(creal.min));
# assert(feq(cr, creal.min));
#
# cr = toCreal(toString(creal.max));
# assert(toString(cr) == toString(creal.max));
# assert(feq(cr, creal.max));
#
# cr = toCreal(toString("1.2345e-5+0i"));
# assert(toString(cr) == toString(1.2345e-5+0i));
# assert(feq(cr, 1.2345e-5+0i));
#
# cr = toCreal(toString("0.0e-0+0i"));
# assert(toString(cr) == toString(0.0e-0+0i));
# assert(cr == 0.0e-0+0i);
# assert(feq(cr, 0.0e-0+0i));
#
# cr = toCreal("123");
# assert(cr == 123);
#
# cr = toCreal("+5");
# assert(cr == 5);
#
# cr = toCreal("-78");
# assert(cr == -78);
# }
#
# /***************************************************************
# * Validates a character string for the following datatypes:
# * float, double, real, ifloat, idouble, and ireal
# * Grammar:
# * ['+'|'-'] string floating-point digit {digit}
# * also allows ".", "i", "f", "L", "e" within the string
# */
# private bit getFloatStrings(in char[] s, out char[] s1)
# {
# char[] s2 = "0";
#
# return getFloatStrings(s, s1, s2);
# }
#
# /***************************************************************
# * Validates and modified a character string for the following datatype:
# * cfloat, cdouble, and creal
# * Grammar:
# * ['+'|'-'] string floating-point digit {digit}
# * also allows ".", "i", "f", "L", "e" within the string
# *
# * s1 returns the first number from the string
# * s2 returns the second (or zeroed out) number from the string
# */
# private bit getFloatStrings(in char[] s, out char[] s1, out char[] s2)
# {
# char[][] a;
# char[] w = s.dup;
# int len = w.length;
#
# if (!len)
# goto Lerr;
#
# // Returns: 0 = error, 1 = ok to use
# bit isFloatingValue(in char[] s)
# {
# char c;
# int len = s.length;
# int periods = 0;
#
# for (int i = 0; i < len; i++)
# {
# c = s[i];
#
# // Set the following characters to lowercase.
# if (c == 'E' || c == 'I' || c == 'F')
# {
# s[i] = c + (cast(char)'a' - 'A');
# c = s[i];
# }
#
# if (c >= '0' && c <= '9')
# continue;
# else if (((c == '-') && (i != len - 1)) && len != 1)
# continue;
# else if (((c == '+') && (i != len - 1)) && len != 1)
# continue;
# else if (((c == 'e') && (i != len - 1)) && len != 1)
# continue;
# else if (c == '.' && periods <= 2 && len != 1)
# {
# periods++;
# continue;
# }
# else if (((c == 'i') && (i == len - 1)) && len != 1)
# continue;
# else if (((c == 'f') && (i == len - 1)) && len != 1 )
# continue;
# else if (((c == 'L') && (i == len - 1)) && len != 1)
# continue;
# else
# return 0;
# }
#
# return 1;
# }
#
# // When "nan" or "nani" just return them.
# if (w == "nan" || w == "nani")
# {
# s1 = w;
# s2 = "0e+0";
# return 1;
# }
#
# // Split the original string out into two strings.
# for (int i = 1; i < len; i++)
# if ((w[i - 1] != 'e' && w[i - 1] != 'E') && w[i] == '+')
# {
# w[i] = '^';
# a = split(w, "^");
# break;
# }
#
# // Handle the case when there's only a single value
# // to work with, and set the other string to zero.
# if (a.length == 0)
# a = split(w ~ "^0e+0", "^");
#
# // Check the first string.
# if (isFloatingValue(a[0]))
# s1 = a[0].dup;
# else
# goto Lerr;
#
# // Check the second string.
# if (isFloatingValue(a[1]))
# s2 = a[1].dup;
# else
# goto Lerr;
#
# // String is good enough to pass
# // into the atof() function. :)
# return 1;
#
# Lerr:
# // Display the original string in the error message.
# conv_error("\"" ~ s ~ "\"");
# return 0;
# }
#
# unittest
# {
# debug(conv) writefln("conv.getFloatStrings.unittest");
# char[] s1;
# char[] s2;
# bit b = 0;
#
# static char[][] errors =
# [
# "",
# "-",
# "+",
# "-+",
# " ",
# " 0",
# "0 ",
# "- 0",
# "1-",
# "xx",
# "123h",
# ];
#
# for (int j = 0; j < errors.length; j++)
# {
# b = 1;
# try
# {
# b = getFloatStrings(errors[j], s1, s2);
# }
# catch (Error e)
# {
# debug(conv) e.print();
# b = 0;
# }
# assert(b == 0);
# }
# }
#
# /****************************************
# * Main function tp compare reals with given precision
# */
# private bit feq(in real rx, in real ry, in real precision)
# {
# if (rx == ry)
# return 1;
#
# if (isnan(rx))
# return cast(bit)isnan(ry);
#
# if (isnan(ry))
# return 0;
#
# return cast(bit)(fabs(rx - ry) <= precision);
# }
#
# /****************************************
# * (Note: Copied here from std.math's mfeq() function for unittesting)
# * Simple function to compare two floating point values
# * to a specified precision.
# * Returns:
# * 1 match
# * 0 nomatch
# */
# private bit feq(in real r1, in real r2)
# {
# if (r1 == r2)
# return 1;
#
# if (isnan(r1))
# return cast(bit)isnan(r2);
#
# if (isnan(r2))
# return 0;
#
# return cast(bit)(feq(r1, r2, 0.000001L));
# }
#
# /****************************************
# * compare ireals with given precision
# */
# private bit feq(in ireal r1, in ireal r2)
# {
# real rx = cast(real)r1;
# real ry = cast(real)r2;
#
# if (rx == ry)
# return 1;
#
# if (isnan(rx))
# return cast(bit)isnan(ry);
#
# if (isnan(ry))
# return 0;
#
# return feq(rx, ry, 0.000001L);
# }
#
# /****************************************
# * compare creals with given precision
# */
# private bit feq(in creal r1, in creal r2)
# {
# real r1a = fabs(cast(real)r1.re - cast(real)r2.re);
# real r2b = fabs(cast(real)r1.im - cast(real)r2.im);
#
# if ((cast(real)r1.re == cast(real)r2.re) &&
# (cast(real)r1.im == cast(real)r2.im))
# return 1;
#
# if (isnan(r1a))
# return cast(bit)isnan(r2b);
#
# if (isnan(r2b))
# return 0;
#
# return feq(r1a, r2b, 0.000001L);
# }
# //*** End of insert ***
-------------------------------------------------------------------
"Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
-------------------------------------------------------------------
MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html
Apr 16 2005
Got a link to a listing without the "#" character at the start of each line? :) TZ "David L. Davis" <SpottedTiger yahoo.com> wrote in message news:d3s8pt$j68$1 digitaldaemon.com...Well, I've been pretty busy this past week reworking all of these "from char[]to floating-point" functions (based on advise gotten from Ben Hinkle) that I'd like Walter to include into std.conv. With the sol purpose of filling in the gap of the missing conversion functions for the following datatypes: float, double, real, ifloat, idouble, ireal, cfloat, cdouble, and creal. If anyone has any interest at all, please at least use an eye-ball or two to look over the code, and better yet, if you have the time, copy and paste this code into dmd v0.121's version of conv.d to test it a bit. Thanks in advance, David L. ====================== # //*** Inserted code after //debug=conv within conv.d *** # private import std.math; // for fabs(), isnan() # private import std.string; // for atof(), split() # debug( conv ) private import std.stdio; // for writefln() and printf() # //*** End of insert *** # # //*** Inserted code at the end-of-file of conv.d *** # /*************************************************************** # * Convert character string to float. # * Grammar: # * ['+'|'-'] digit {digit} # */ # float toFloat(in char[] s) # { # real r; # float f; # # if (!s.length) # goto Lerr; # # r = toReal(s); # f = cast(float)r; # # if (feq(cast(real)f, r) != 1) # if (toString(f) != toString(r)) # goto Loverflow; # # return cast(float)r; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return 0f; # } # # unittest # { # debug( conv ) writefln( "conv.toFloat.unittest" ); # float f; # # f = toFloat( "123" ); # assert( f == 123f ); # f = toFloat( "+123" ); # assert( f == +123f ); # f = toFloat( "-123" ); # assert( f == -123f ); # f = toFloat( "123e+2" ); # assert( f == 123e+2f ); # # f = toFloat( "123e-2" ); # assert( f == 123e-2f ); # f = toFloat( "123." ); # assert( f == 123.f ); # f = toFloat( ".456" ); # assert( f == .456f ); # # //Min and Max values # f = toFloat("1.17549e-38"); # assert(feq(cast(real)f, cast(real)1.17549e-38)); # assert(feq(cast(real)f, cast(real)float.min)); # f = toFloat("3.40282e+38"); # assert(toString(f) == toString(3.40282e+38)); # # //nan # f = toFloat("nan"); # assert(toString(f) == toString(float.nan)); # } # # /*************************************************************** # * Convert character string to double. # * Grammar: # * ['+'|'-'] digit {digit} # */ # double toDouble(in char[] s) # { # real r; # double d; # # if (!s.length) # goto Lerr; # # r = toReal(s); # d = cast(double)r; # # if (feq(r, cast(real)d) != 1) # if (toString(d) != toString(r)) # goto Loverflow; # # return cast(double)r; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return 0; # } # # unittest # { # debug( conv ) writefln( "conv.toDouble.unittest" ); # double d; # # d = toDouble( "123" ); # assert( d == 123 ); # d = toDouble( "+123" ); # assert( d == +123 ); # d = toDouble( "-123" ); # assert( d == -123 ); # d = toDouble( "123e2" ); # assert( d == 123e2); # d = toDouble( "123e-2" ); # assert( d == 123e-2 ); # d = toDouble( "123." ); # assert( d == 123. ); # d = toDouble( ".456" ); # assert( d == .456 ); # d = toDouble( "1.23456E+2" ); # assert( d == 1.23456E+2 ); # # //Min and Max values # d = toDouble("2.22507e-308"); # assert(feq(cast(real)d, cast(real)2.22507e-308)); # assert(feq(cast(real)d, cast(real)double.min)); # d = toDouble("1.79769e+308"); # assert(toString(d) == toString(1.79769e+308)); # assert(toString(d) == toString(double.max)); # # //nan # d = toDouble("nan"); # assert(toString(d) == toString(double.nan)); # } # # /*************************************************************** # * Convert character string to real. # * Grammar: # * ['+'|'-'] digit {digit} # */ # real toReal(in char[] s) # { # char[] sx; # bit b; # # if (!s.length) # goto Lerr; # # b = getFloatStrings(s, sx); # # if (b == 0) # goto Lerr; # # return atof(sx); # # Lerr: # conv_error(s); # return 0.0L; # } # # unittest # { # debug(conv) writefln("conv.toReal.unittest"); # real r; # # r = toReal("123"); # assert(r == 123L); # r = toReal("+123"); # assert(r == 123L); # r = toReal("-123"); # assert(r == -123L); # r = toReal("123e2"); # assert(feq(r, 123e2L)); # r = toReal("123e-2"); # assert(feq(r, 1.23L)); # r = toReal("123."); # assert(r == 123L); # r = toReal(".456"); # assert(r == .456L); # # r = toReal("1.23456e+2"); # assert(feq(r, 1.23456e+2L)); # r = toReal(toString(real.max / 2L)); # assert(toString(r) == toString(real.max / 2L)); # # //Min and Max values # r = toReal(toString(real.min)); # assert(toString(r) == toString(real.min)); # r = toReal(toString(real.max)); # assert(toString(r) == toString(real.max)); # # //nan # r = toReal("nan"); # assert(toString(r) == toString(real.nan)); # } # # /*************************************************************** # * Convert character string to ifloat. # * Grammar: # * ['+'|'-'] digit {digit} # */ # ifloat toIfloat(in char[] s) # { # real r; # ireal ir; # ifloat ift; # # if (!s.length) # goto Lerr; # # r = toReal(s); # ir = cast(ireal)(r * 1.0i); # ift = cast(ifloat)(r * 1.0i); # # if (feq(ir, cast(ireal)ift) != 1) # goto Loverflow; # # return ift; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return cast(ifloat)0.0i; # } # # unittest # { # debug(conv) writefln("conv.toIfloat.unittest"); # ifloat ift; # # ift = toIfloat(toString(ifloat.min)); # # assert(toString(ift) == toString(ifloat.min) ); # assert(feq(cast(ireal)ift, cast(ireal)ifloat.min)); # # ift = toIfloat(toString(ifloat.max)); # assert(toString(ift) == toString(ifloat.max)); # assert(feq(cast(ireal)ift, cast(ireal)ifloat.max)); # # ift = toIfloat(toString(123.45)); # assert(toString(ift) == toString(123.45i)); # # ift = toIfloat(toString(456.77i)); # assert(toString(ift) == toString(456.77i)); # # ift = toIfloat(toString(ifloat.nan)); # assert(toString(ift.nan) == toString(ifloat.nan)); # assert(feq(cast(ireal)ift, cast(ireal)ifloat.nan)); # } # # /*************************************************************** # * Convert character string to idouble. # * Grammar: # * ['+'|'-'] digit {digit} # */ # idouble toIdouble(in char[] s) # { # real r; # ireal ir; # idouble id; # # if (!s.length) # goto Lerr; # # r = toReal(s); # ir = cast(ireal)(r * 1.0i); # id = cast(idouble)(r * 1.0i); # # if (feq(ir, cast(ireal)id) != 1) # goto Loverflow; # # return id; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return cast(idouble)0.0i; # } # # unittest # { # debug(conv) writefln("conv.toIdouble.unittest"); # idouble id; # # id = toIdouble(toString(idouble.min)); # assert(toString( id ) == toString(idouble.min)); # assert(feq(cast(ireal)id.re, cast(ireal)idouble.min.re)); # assert(feq(cast(ireal)id.im, cast(ireal)idouble.min.im)); # # id = toIdouble(toString(idouble.max)); # assert(toString(id) == toString(idouble.max)); # assert(feq(cast(ireal)id.re, cast(ireal)idouble.max.re)); # assert(feq(cast(ireal)id.im, cast(ireal)idouble.max.im)); # # id = toIdouble(toString("123.45")); # assert(id == 123.45i); # # id = toIdouble(toString(idouble.nan)); # assert(toString(id.nan) == toString(idouble.nan)); # } # # /*************************************************************** # * Convert character string to ireal. # * Grammar: # * ['+'|'-'] digit {digit} # */ # ireal toIreal(in char[] s) # { # real r; # ireal ir; # # if (!s.length) # goto Lerr; # # r = toReal(s); # # ir = cast(ireal)(r * 1.0i); # # return ir; # # Lerr: # conv_error(s); # return cast(ireal)0.0i; # } # # unittest # { # debug(conv) writefln("conv.toIreal.unittest"); # ireal ir; # # ir = toIreal(toString(ireal.min)); # assert(toString(ir) == toString(ireal.min)); # assert(feq(cast(real)ir.re, cast(real)ireal.min.re)); # assert(feq(cast(real)ir.im, cast(real)ireal.min.im)); # # ir = toIreal(toString(ireal.max)); # assert(toString(ir) == toString(ireal.max)); # assert(feq(cast(real)ir.re, cast(real)ireal.max.re)); # # ir = toIreal(toString("123.45")); # assert(feq(cast(real)ir.re, cast(real)123.45i)); # # ir = toIreal(toString(ireal.nan)); # assert(toString(ir.nan) == toString(ireal.nan)); # } # # /*************************************************************** # * Convert character string to cfloat. # * Grammar: # * ['+'|'-'] digit {digit} # */ # cfloat toCfloat(in char[] s) # { # char[] s1; # char[] s2; # real r1; # real r2; # creal cr; # cfloat cf; # bit b = 0; # # if (!s.length) # goto Lerr; # # b = getFloatStrings(s, s1, s2); # # if (b == 0) # goto Lerr; # # r1 = atof(s1); # r2 = atof(s2); # # cr = cast(creal)cast(creal)r1 + cast(creal)(r2 * 1.0i); # cf = cast(cfloat)r1 + cast(cfloat)(r2 * 1.0i); # # if (feq(cr, cast(creal)cf) != 1) # goto Loverflow; # # return cf; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return cast(cfloat)0.0e-0+0i; # } # # unittest # { # debug(conv) writefln("conv.toCfloat.unittest"); # cfloat cf; # # cf = toCfloat(toString(cfloat.min)); # assert(toString(cf) == toString(cfloat.min)); # # cf = toCfloat(toString(cfloat.max)); # assert(toString(cf) == toString(cfloat.max)); # # cf = toCfloat(toString("1.2345e-5+0i")); # assert(toString(cf) == toString(1.2345e-5+0i)); # assert(feq(cf, 1.2345e-5+0i)); # } # # /*************************************************************** # * Convert character string to cdouble. # * Grammar: # * ['+'|'-'] digit {digit} # */ # cdouble toCdouble(in char[] s) # { # char[] s1; # char[] s2; # real r1; # real r2; # creal cr; # cdouble cd; # bit b = 0; # # if (!s.length) # goto Lerr; # # b = getFloatStrings(s, s1, s2); # # if (b == 0) # goto Lerr; # # r1 = atof(s1); # r2 = atof(s2); # # cr = cast(creal)cast(creal)r1 + cast(creal)(r2 * 1.0i); # cd = cast(cdouble)r1 + cast(cdouble)(r2 * 1.0i); # # if (feq(cr, cast(creal)cd) != 1) # goto Loverflow; # # return cd; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return cast(cdouble)0.0e-0+0i; # } # # unittest # { # debug(conv) writefln("conv.toCdouble.unittest"); # cdouble cd; # # cd = toCdouble(toString(cdouble.min)); # assert(toString(cd) == toString(cdouble.min)); # # cd = toCdouble(toString(cdouble.max)); # assert(toString( cd ) == toString(cdouble.max)); # # cd = toCdouble(toString("1.2345e-5+0i")); # assert(toString( cd ) == toString(1.2345e-5+0i)); # assert(feq(cd, 1.2345e-5+0i)); # } # # /*************************************************************** # * Convert character string to creal. # * Grammar: # * ['+'|'-'] digit {digit} # */ # creal toCreal(in char[] s) # { # char[] s1; # char[] s2; # real r1; # real r2; # creal cr; # bit b = 0; # # if (!s.length) # goto Lerr; # # b = getFloatStrings(s, s1, s2); # # if (b == 0) # goto Lerr; # # r1 = atof(s1); # r2 = atof(s2); # # if (r2 != 0.0) # cr = cast(creal)(r1 + (r2 * 1.0i)); # else # cr = cast(creal)(r1 + cast(creal)0.0i); # # return cr; # # Lerr: # conv_error(s); # return cast(creal)0.0e-0+0i; # } # # unittest # { # debug(conv) writefln("conv.toCreal.unittest"); # creal cr; # # cr = toCreal(toString(creal.min)); # assert(toString(cr) == toString(creal.min)); # assert(feq(cr, creal.min)); # # cr = toCreal(toString(creal.max)); # assert(toString(cr) == toString(creal.max)); # assert(feq(cr, creal.max)); # # cr = toCreal(toString("1.2345e-5+0i")); # assert(toString(cr) == toString(1.2345e-5+0i)); # assert(feq(cr, 1.2345e-5+0i)); # # cr = toCreal(toString("0.0e-0+0i")); # assert(toString(cr) == toString(0.0e-0+0i)); # assert(cr == 0.0e-0+0i); # assert(feq(cr, 0.0e-0+0i)); # # cr = toCreal("123"); # assert(cr == 123); # # cr = toCreal("+5"); # assert(cr == 5); # # cr = toCreal("-78"); # assert(cr == -78); # } # # /*************************************************************** # * Validates a character string for the following datatypes: # * float, double, real, ifloat, idouble, and ireal # * Grammar: # * ['+'|'-'] string floating-point digit {digit} # * also allows ".", "i", "f", "L", "e" within the string # */ # private bit getFloatStrings(in char[] s, out char[] s1) # { # char[] s2 = "0"; # # return getFloatStrings(s, s1, s2); # } # # /*************************************************************** # * Validates and modified a character string for the following datatype: # * cfloat, cdouble, and creal # * Grammar: # * ['+'|'-'] string floating-point digit {digit} # * also allows ".", "i", "f", "L", "e" within the string # * # * s1 returns the first number from the string # * s2 returns the second (or zeroed out) number from the string # */ # private bit getFloatStrings(in char[] s, out char[] s1, out char[] s2) # { # char[][] a; # char[] w = s.dup; # int len = w.length; # # if (!len) # goto Lerr; # # // Returns: 0 = error, 1 = ok to use # bit isFloatingValue(in char[] s) # { # char c; # int len = s.length; # int periods = 0; # # for (int i = 0; i < len; i++) # { # c = s[i]; # # // Set the following characters to lowercase. # if (c == 'E' || c == 'I' || c == 'F') # { # s[i] = c + (cast(char)'a' - 'A'); # c = s[i]; # } # # if (c >= '0' && c <= '9') # continue; # else if (((c == '-') && (i != len - 1)) && len != 1) # continue; # else if (((c == '+') && (i != len - 1)) && len != 1) # continue; # else if (((c == 'e') && (i != len - 1)) && len != 1) # continue; # else if (c == '.' && periods <= 2 && len != 1) # { # periods++; # continue; # } # else if (((c == 'i') && (i == len - 1)) && len != 1) # continue; # else if (((c == 'f') && (i == len - 1)) && len != 1 ) # continue; # else if (((c == 'L') && (i == len - 1)) && len != 1) # continue; # else # return 0; # } # # return 1; # } # # // When "nan" or "nani" just return them. # if (w == "nan" || w == "nani") # { # s1 = w; # s2 = "0e+0"; # return 1; # } # # // Split the original string out into two strings. # for (int i = 1; i < len; i++) # if ((w[i - 1] != 'e' && w[i - 1] != 'E') && w[i] == '+') # { # w[i] = '^'; # a = split(w, "^"); # break; # } # # // Handle the case when there's only a single value # // to work with, and set the other string to zero. # if (a.length == 0) # a = split(w ~ "^0e+0", "^"); # # // Check the first string. # if (isFloatingValue(a[0])) # s1 = a[0].dup; # else # goto Lerr; # # // Check the second string. # if (isFloatingValue(a[1])) # s2 = a[1].dup; # else # goto Lerr; # # // String is good enough to pass # // into the atof() function. :) # return 1; # # Lerr: # // Display the original string in the error message. # conv_error("\"" ~ s ~ "\""); # return 0; # } # # unittest # { # debug(conv) writefln("conv.getFloatStrings.unittest"); # char[] s1; # char[] s2; # bit b = 0; # # static char[][] errors = # [ # "", # "-", # "+", # "-+", # " ", # " 0", # "0 ", # "- 0", # "1-", # "xx", # "123h", # ]; # # for (int j = 0; j < errors.length; j++) # { # b = 1; # try # { # b = getFloatStrings(errors[j], s1, s2); # } # catch (Error e) # { # debug(conv) e.print(); # b = 0; # } # assert(b == 0); # } # } # # /**************************************** # * Main function tp compare reals with given precision # */ # private bit feq(in real rx, in real ry, in real precision) # { # if (rx == ry) # return 1; # # if (isnan(rx)) # return cast(bit)isnan(ry); # # if (isnan(ry)) # return 0; # # return cast(bit)(fabs(rx - ry) <= precision); # } # # /**************************************** # * (Note: Copied here from std.math's mfeq() function for unittesting) # * Simple function to compare two floating point values # * to a specified precision. # * Returns: # * 1 match # * 0 nomatch # */ # private bit feq(in real r1, in real r2) # { # if (r1 == r2) # return 1; # # if (isnan(r1)) # return cast(bit)isnan(r2); # # if (isnan(r2)) # return 0; # # return cast(bit)(feq(r1, r2, 0.000001L)); # } # # /**************************************** # * compare ireals with given precision # */ # private bit feq(in ireal r1, in ireal r2) # { # real rx = cast(real)r1; # real ry = cast(real)r2; # # if (rx == ry) # return 1; # # if (isnan(rx)) # return cast(bit)isnan(ry); # # if (isnan(ry)) # return 0; # # return feq(rx, ry, 0.000001L); # } # # /**************************************** # * compare creals with given precision # */ # private bit feq(in creal r1, in creal r2) # { # real r1a = fabs(cast(real)r1.re - cast(real)r2.re); # real r2b = fabs(cast(real)r1.im - cast(real)r2.im); # # if ((cast(real)r1.re == cast(real)r2.re) && # (cast(real)r1.im == cast(real)r2.im)) # return 1; # # if (isnan(r1a)) # return cast(bit)isnan(r2b); # # if (isnan(r2b)) # return 0; # # return feq(r1a, r2b, 0.000001L); # } # //*** End of insert *** ------------------------------------------------------------------- "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!" ------------------------------------------------------------------- MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html
Apr 21 2005
In article <d48dvl$5l9$1 digitaldaemon.com>, TechnoZeus says...Got a link to a listing without the "#" character at the start of each line? :)
No need, just use the following util to process the file. // strip.d // useage: strip.exe <infile> <outfile> import std.file; import std.regexp; void main(char[][] args){ if(args.length != 3) return; std.file.write(args[2],std.regexp.sub(cast(char[])std.file.read(args[1]),"^#","","gmi")); } - EricAnderton at yahoo
Apr 21 2005
Thanks. :) TZ "pragma" <pragma_member pathlink.com> wrote in message news:d48gbv$7r4$1 digitaldaemon.com...In article <d48dvl$5l9$1 digitaldaemon.com>, TechnoZeus says...Got a link to a listing without the "#" character at the start of each line? :)
No need, just use the following util to process the file. // strip.d // useage: strip.exe <infile> <outfile> import std.file; import std.regexp; void main(char[][] args){ if(args.length != 3) return; std.file.write(args[2],std.regexp.sub(cast(char[])std.file.read(args[1]),"^#","","gmi")); } - EricAnderton at yahoo
Apr 21 2005
It's looking better and better. I hope Walter eventually takes it. My comments from going over it with a fine-tooth comb: 1) when returning or testing bit values use true/false instead of 0/1 (or just test the value without having ==true at all). 2) in getFloatStrings if a copy of the strings is really needed try to use a buffer on the stack instead of always dup'ing. Converting a string to a numeric value shouldn't generate garbage unless really needed. For example the calling functions can have a buffer it passes to getFloatString and if it isn't long enough getFloatStrings can reallocate. Also I wouldn't dup the return strings - just let them live as slices if at all possible. 3) in the overflow checking can things like if (!feq(cast(real)f,r)) ... overflow... be replaced with if (r > float.max) ... overflow ... I'm not exactly sure what the original test is catching as overflow - can you explain it in words? 4) can the code cast(ireal)r*1.0i) be replaced with cast(ireal)r or maybe cast(ireal)cast(real)r if that doesn't work? 5) in a few of the toCDouble and friends there are two cast(creal) in a row. Are they needed? thanks for taking a crack at this! -Ben "David L. Davis" <SpottedTiger yahoo.com> wrote in message news:d3s8pt$j68$1 digitaldaemon.com...Well, I've been pretty busy this past week reworking all of these "from char[]to floating-point" functions (based on advise gotten from Ben Hinkle) that I'd like Walter to include into std.conv. With the sol purpose of filling in the gap of the missing conversion functions for the following datatypes: float, double, real, ifloat, idouble, ireal, cfloat, cdouble, and creal. If anyone has any interest at all, please at least use an eye-ball or two to look over the code, and better yet, if you have the time, copy and paste this code into dmd v0.121's version of conv.d to test it a bit. Thanks in advance, David L. ====================== # //*** Inserted code after //debug=conv within conv.d *** # private import std.math; // for fabs(), isnan() # private import std.string; // for atof(), split() # debug( conv ) private import std.stdio; // for writefln() and printf() # //*** End of insert *** # # //*** Inserted code at the end-of-file of conv.d *** # /*************************************************************** # * Convert character string to float. # * Grammar: # * ['+'|'-'] digit {digit} # */ # float toFloat(in char[] s) # { # real r; # float f; # # if (!s.length) # goto Lerr; # # r = toReal(s); # f = cast(float)r; # # if (feq(cast(real)f, r) != 1) # if (toString(f) != toString(r)) # goto Loverflow; # # return cast(float)r; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return 0f; # } # # unittest # { # debug( conv ) writefln( "conv.toFloat.unittest" ); # float f; # # f = toFloat( "123" ); # assert( f == 123f ); # f = toFloat( "+123" ); # assert( f == +123f ); # f = toFloat( "-123" ); # assert( f == -123f ); # f = toFloat( "123e+2" ); # assert( f == 123e+2f ); # # f = toFloat( "123e-2" ); # assert( f == 123e-2f ); # f = toFloat( "123." ); # assert( f == 123.f ); # f = toFloat( ".456" ); # assert( f == .456f ); # # //Min and Max values # f = toFloat("1.17549e-38"); # assert(feq(cast(real)f, cast(real)1.17549e-38)); # assert(feq(cast(real)f, cast(real)float.min)); # f = toFloat("3.40282e+38"); # assert(toString(f) == toString(3.40282e+38)); # # //nan # f = toFloat("nan"); # assert(toString(f) == toString(float.nan)); # } # # /*************************************************************** # * Convert character string to double. # * Grammar: # * ['+'|'-'] digit {digit} # */ # double toDouble(in char[] s) # { # real r; # double d; # # if (!s.length) # goto Lerr; # # r = toReal(s); # d = cast(double)r; # # if (feq(r, cast(real)d) != 1) # if (toString(d) != toString(r)) # goto Loverflow; # # return cast(double)r; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return 0; # } # # unittest # { # debug( conv ) writefln( "conv.toDouble.unittest" ); # double d; # # d = toDouble( "123" ); # assert( d == 123 ); # d = toDouble( "+123" ); # assert( d == +123 ); # d = toDouble( "-123" ); # assert( d == -123 ); # d = toDouble( "123e2" ); # assert( d == 123e2); # d = toDouble( "123e-2" ); # assert( d == 123e-2 ); # d = toDouble( "123." ); # assert( d == 123. ); # d = toDouble( ".456" ); # assert( d == .456 ); # d = toDouble( "1.23456E+2" ); # assert( d == 1.23456E+2 ); # # //Min and Max values # d = toDouble("2.22507e-308"); # assert(feq(cast(real)d, cast(real)2.22507e-308)); # assert(feq(cast(real)d, cast(real)double.min)); # d = toDouble("1.79769e+308"); # assert(toString(d) == toString(1.79769e+308)); # assert(toString(d) == toString(double.max)); # # //nan # d = toDouble("nan"); # assert(toString(d) == toString(double.nan)); # } # # /*************************************************************** # * Convert character string to real. # * Grammar: # * ['+'|'-'] digit {digit} # */ # real toReal(in char[] s) # { # char[] sx; # bit b; # # if (!s.length) # goto Lerr; # # b = getFloatStrings(s, sx); # # if (b == 0) # goto Lerr; # # return atof(sx); # # Lerr: # conv_error(s); # return 0.0L; # } # # unittest # { # debug(conv) writefln("conv.toReal.unittest"); # real r; # # r = toReal("123"); # assert(r == 123L); # r = toReal("+123"); # assert(r == 123L); # r = toReal("-123"); # assert(r == -123L); # r = toReal("123e2"); # assert(feq(r, 123e2L)); # r = toReal("123e-2"); # assert(feq(r, 1.23L)); # r = toReal("123."); # assert(r == 123L); # r = toReal(".456"); # assert(r == .456L); # # r = toReal("1.23456e+2"); # assert(feq(r, 1.23456e+2L)); # r = toReal(toString(real.max / 2L)); # assert(toString(r) == toString(real.max / 2L)); # # //Min and Max values # r = toReal(toString(real.min)); # assert(toString(r) == toString(real.min)); # r = toReal(toString(real.max)); # assert(toString(r) == toString(real.max)); # # //nan # r = toReal("nan"); # assert(toString(r) == toString(real.nan)); # } # # /*************************************************************** # * Convert character string to ifloat. # * Grammar: # * ['+'|'-'] digit {digit} # */ # ifloat toIfloat(in char[] s) # { # real r; # ireal ir; # ifloat ift; # # if (!s.length) # goto Lerr; # # r = toReal(s); # ir = cast(ireal)(r * 1.0i); # ift = cast(ifloat)(r * 1.0i); # # if (feq(ir, cast(ireal)ift) != 1) # goto Loverflow; # # return ift; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return cast(ifloat)0.0i; # } # # unittest # { # debug(conv) writefln("conv.toIfloat.unittest"); # ifloat ift; # # ift = toIfloat(toString(ifloat.min)); # # assert(toString(ift) == toString(ifloat.min) ); # assert(feq(cast(ireal)ift, cast(ireal)ifloat.min)); # # ift = toIfloat(toString(ifloat.max)); # assert(toString(ift) == toString(ifloat.max)); # assert(feq(cast(ireal)ift, cast(ireal)ifloat.max)); # # ift = toIfloat(toString(123.45)); # assert(toString(ift) == toString(123.45i)); # # ift = toIfloat(toString(456.77i)); # assert(toString(ift) == toString(456.77i)); # # ift = toIfloat(toString(ifloat.nan)); # assert(toString(ift.nan) == toString(ifloat.nan)); # assert(feq(cast(ireal)ift, cast(ireal)ifloat.nan)); # } # # /*************************************************************** # * Convert character string to idouble. # * Grammar: # * ['+'|'-'] digit {digit} # */ # idouble toIdouble(in char[] s) # { # real r; # ireal ir; # idouble id; # # if (!s.length) # goto Lerr; # # r = toReal(s); # ir = cast(ireal)(r * 1.0i); # id = cast(idouble)(r * 1.0i); # # if (feq(ir, cast(ireal)id) != 1) # goto Loverflow; # # return id; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return cast(idouble)0.0i; # } # # unittest # { # debug(conv) writefln("conv.toIdouble.unittest"); # idouble id; # # id = toIdouble(toString(idouble.min)); # assert(toString( id ) == toString(idouble.min)); # assert(feq(cast(ireal)id.re, cast(ireal)idouble.min.re)); # assert(feq(cast(ireal)id.im, cast(ireal)idouble.min.im)); # # id = toIdouble(toString(idouble.max)); # assert(toString(id) == toString(idouble.max)); # assert(feq(cast(ireal)id.re, cast(ireal)idouble.max.re)); # assert(feq(cast(ireal)id.im, cast(ireal)idouble.max.im)); # # id = toIdouble(toString("123.45")); # assert(id == 123.45i); # # id = toIdouble(toString(idouble.nan)); # assert(toString(id.nan) == toString(idouble.nan)); # } # # /*************************************************************** # * Convert character string to ireal. # * Grammar: # * ['+'|'-'] digit {digit} # */ # ireal toIreal(in char[] s) # { # real r; # ireal ir; # # if (!s.length) # goto Lerr; # # r = toReal(s); # # ir = cast(ireal)(r * 1.0i); # # return ir; # # Lerr: # conv_error(s); # return cast(ireal)0.0i; # } # # unittest # { # debug(conv) writefln("conv.toIreal.unittest"); # ireal ir; # # ir = toIreal(toString(ireal.min)); # assert(toString(ir) == toString(ireal.min)); # assert(feq(cast(real)ir.re, cast(real)ireal.min.re)); # assert(feq(cast(real)ir.im, cast(real)ireal.min.im)); # # ir = toIreal(toString(ireal.max)); # assert(toString(ir) == toString(ireal.max)); # assert(feq(cast(real)ir.re, cast(real)ireal.max.re)); # # ir = toIreal(toString("123.45")); # assert(feq(cast(real)ir.re, cast(real)123.45i)); # # ir = toIreal(toString(ireal.nan)); # assert(toString(ir.nan) == toString(ireal.nan)); # } # # /*************************************************************** # * Convert character string to cfloat. # * Grammar: # * ['+'|'-'] digit {digit} # */ # cfloat toCfloat(in char[] s) # { # char[] s1; # char[] s2; # real r1; # real r2; # creal cr; # cfloat cf; # bit b = 0; # # if (!s.length) # goto Lerr; # # b = getFloatStrings(s, s1, s2); # # if (b == 0) # goto Lerr; # # r1 = atof(s1); # r2 = atof(s2); # # cr = cast(creal)cast(creal)r1 + cast(creal)(r2 * 1.0i); # cf = cast(cfloat)r1 + cast(cfloat)(r2 * 1.0i); # # if (feq(cr, cast(creal)cf) != 1) # goto Loverflow; # # return cf; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return cast(cfloat)0.0e-0+0i; # } # # unittest # { # debug(conv) writefln("conv.toCfloat.unittest"); # cfloat cf; # # cf = toCfloat(toString(cfloat.min)); # assert(toString(cf) == toString(cfloat.min)); # # cf = toCfloat(toString(cfloat.max)); # assert(toString(cf) == toString(cfloat.max)); # # cf = toCfloat(toString("1.2345e-5+0i")); # assert(toString(cf) == toString(1.2345e-5+0i)); # assert(feq(cf, 1.2345e-5+0i)); # } # # /*************************************************************** # * Convert character string to cdouble. # * Grammar: # * ['+'|'-'] digit {digit} # */ # cdouble toCdouble(in char[] s) # { # char[] s1; # char[] s2; # real r1; # real r2; # creal cr; # cdouble cd; # bit b = 0; # # if (!s.length) # goto Lerr; # # b = getFloatStrings(s, s1, s2); # # if (b == 0) # goto Lerr; # # r1 = atof(s1); # r2 = atof(s2); # # cr = cast(creal)cast(creal)r1 + cast(creal)(r2 * 1.0i); # cd = cast(cdouble)r1 + cast(cdouble)(r2 * 1.0i); # # if (feq(cr, cast(creal)cd) != 1) # goto Loverflow; # # return cd; # # Loverflow: # conv_overflow(s); # # Lerr: # conv_error(s); # return cast(cdouble)0.0e-0+0i; # } # # unittest # { # debug(conv) writefln("conv.toCdouble.unittest"); # cdouble cd; # # cd = toCdouble(toString(cdouble.min)); # assert(toString(cd) == toString(cdouble.min)); # # cd = toCdouble(toString(cdouble.max)); # assert(toString( cd ) == toString(cdouble.max)); # # cd = toCdouble(toString("1.2345e-5+0i")); # assert(toString( cd ) == toString(1.2345e-5+0i)); # assert(feq(cd, 1.2345e-5+0i)); # } # # /*************************************************************** # * Convert character string to creal. # * Grammar: # * ['+'|'-'] digit {digit} # */ # creal toCreal(in char[] s) # { # char[] s1; # char[] s2; # real r1; # real r2; # creal cr; # bit b = 0; # # if (!s.length) # goto Lerr; # # b = getFloatStrings(s, s1, s2); # # if (b == 0) # goto Lerr; # # r1 = atof(s1); # r2 = atof(s2); # # if (r2 != 0.0) # cr = cast(creal)(r1 + (r2 * 1.0i)); # else # cr = cast(creal)(r1 + cast(creal)0.0i); # # return cr; # # Lerr: # conv_error(s); # return cast(creal)0.0e-0+0i; # } # # unittest # { # debug(conv) writefln("conv.toCreal.unittest"); # creal cr; # # cr = toCreal(toString(creal.min)); # assert(toString(cr) == toString(creal.min)); # assert(feq(cr, creal.min)); # # cr = toCreal(toString(creal.max)); # assert(toString(cr) == toString(creal.max)); # assert(feq(cr, creal.max)); # # cr = toCreal(toString("1.2345e-5+0i")); # assert(toString(cr) == toString(1.2345e-5+0i)); # assert(feq(cr, 1.2345e-5+0i)); # # cr = toCreal(toString("0.0e-0+0i")); # assert(toString(cr) == toString(0.0e-0+0i)); # assert(cr == 0.0e-0+0i); # assert(feq(cr, 0.0e-0+0i)); # # cr = toCreal("123"); # assert(cr == 123); # # cr = toCreal("+5"); # assert(cr == 5); # # cr = toCreal("-78"); # assert(cr == -78); # } # # /*************************************************************** # * Validates a character string for the following datatypes: # * float, double, real, ifloat, idouble, and ireal # * Grammar: # * ['+'|'-'] string floating-point digit {digit} # * also allows ".", "i", "f", "L", "e" within the string # */ # private bit getFloatStrings(in char[] s, out char[] s1) # { # char[] s2 = "0"; # # return getFloatStrings(s, s1, s2); # } # # /*************************************************************** # * Validates and modified a character string for the following datatype: # * cfloat, cdouble, and creal # * Grammar: # * ['+'|'-'] string floating-point digit {digit} # * also allows ".", "i", "f", "L", "e" within the string # * # * s1 returns the first number from the string # * s2 returns the second (or zeroed out) number from the string # */ # private bit getFloatStrings(in char[] s, out char[] s1, out char[] s2) # { # char[][] a; # char[] w = s.dup; # int len = w.length; # # if (!len) # goto Lerr; # # // Returns: 0 = error, 1 = ok to use # bit isFloatingValue(in char[] s) # { # char c; # int len = s.length; # int periods = 0; # # for (int i = 0; i < len; i++) # { # c = s[i]; # # // Set the following characters to lowercase. # if (c == 'E' || c == 'I' || c == 'F') # { # s[i] = c + (cast(char)'a' - 'A'); # c = s[i]; # } # # if (c >= '0' && c <= '9') # continue; # else if (((c == '-') && (i != len - 1)) && len != 1) # continue; # else if (((c == '+') && (i != len - 1)) && len != 1) # continue; # else if (((c == 'e') && (i != len - 1)) && len != 1) # continue; # else if (c == '.' && periods <= 2 && len != 1) # { # periods++; # continue; # } # else if (((c == 'i') && (i == len - 1)) && len != 1) # continue; # else if (((c == 'f') && (i == len - 1)) && len != 1 ) # continue; # else if (((c == 'L') && (i == len - 1)) && len != 1) # continue; # else # return 0; # } # # return 1; # } # # // When "nan" or "nani" just return them. # if (w == "nan" || w == "nani") # { # s1 = w; # s2 = "0e+0"; # return 1; # } # # // Split the original string out into two strings. # for (int i = 1; i < len; i++) # if ((w[i - 1] != 'e' && w[i - 1] != 'E') && w[i] == '+') # { # w[i] = '^'; # a = split(w, "^"); # break; # } # # // Handle the case when there's only a single value # // to work with, and set the other string to zero. # if (a.length == 0) # a = split(w ~ "^0e+0", "^"); # # // Check the first string. # if (isFloatingValue(a[0])) # s1 = a[0].dup; # else # goto Lerr; # # // Check the second string. # if (isFloatingValue(a[1])) # s2 = a[1].dup; # else # goto Lerr; # # // String is good enough to pass # // into the atof() function. :) # return 1; # # Lerr: # // Display the original string in the error message. # conv_error("\"" ~ s ~ "\""); # return 0; # } # # unittest # { # debug(conv) writefln("conv.getFloatStrings.unittest"); # char[] s1; # char[] s2; # bit b = 0; # # static char[][] errors = # [ # "", # "-", # "+", # "-+", # " ", # " 0", # "0 ", # "- 0", # "1-", # "xx", # "123h", # ]; # # for (int j = 0; j < errors.length; j++) # { # b = 1; # try # { # b = getFloatStrings(errors[j], s1, s2); # } # catch (Error e) # { # debug(conv) e.print(); # b = 0; # } # assert(b == 0); # } # } # # /**************************************** # * Main function tp compare reals with given precision # */ # private bit feq(in real rx, in real ry, in real precision) # { # if (rx == ry) # return 1; # # if (isnan(rx)) # return cast(bit)isnan(ry); # # if (isnan(ry)) # return 0; # # return cast(bit)(fabs(rx - ry) <= precision); # } # # /**************************************** # * (Note: Copied here from std.math's mfeq() function for unittesting) # * Simple function to compare two floating point values # * to a specified precision. # * Returns: # * 1 match # * 0 nomatch # */ # private bit feq(in real r1, in real r2) # { # if (r1 == r2) # return 1; # # if (isnan(r1)) # return cast(bit)isnan(r2); # # if (isnan(r2)) # return 0; # # return cast(bit)(feq(r1, r2, 0.000001L)); # } # # /**************************************** # * compare ireals with given precision # */ # private bit feq(in ireal r1, in ireal r2) # { # real rx = cast(real)r1; # real ry = cast(real)r2; # # if (rx == ry) # return 1; # # if (isnan(rx)) # return cast(bit)isnan(ry); # # if (isnan(ry)) # return 0; # # return feq(rx, ry, 0.000001L); # } # # /**************************************** # * compare creals with given precision # */ # private bit feq(in creal r1, in creal r2) # { # real r1a = fabs(cast(real)r1.re - cast(real)r2.re); # real r2b = fabs(cast(real)r1.im - cast(real)r2.im); # # if ((cast(real)r1.re == cast(real)r2.re) && # (cast(real)r1.im == cast(real)r2.im)) # return 1; # # if (isnan(r1a)) # return cast(bit)isnan(r2b); # # if (isnan(r2b)) # return 0; # # return feq(r1a, r2b, 0.000001L); # } # //*** End of insert *** ------------------------------------------------------------------- "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!" ------------------------------------------------------------------- MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html
Apr 22 2005
Some comments about getFloatStrings. I also looked at the definition of atof in std.string. It calls strtold and throws away the end ptr. You might want to directly call strtold and use the end ptr instead of calling atof. Or, since atof calls toStringz, you might want to manage that better, too, since toStringz can (and probably will) dup strings.# /*************************************************************** # * Validates and modified a character string for the following datatype: # * cfloat, cdouble, and creal # * Grammar: # * ['+'|'-'] string floating-point digit {digit} # * also allows ".", "i", "f", "L", "e" within the string
Why look for f and L?# * # * s1 returns the first number from the string # * s2 returns the second (or zeroed out) number from the string # */ # private bit getFloatStrings(in char[] s, out char[] s1, out char[] s2) # { # char[][] a; # char[] w = s.dup; # int len = w.length; # # if (!len) # goto Lerr; # # // Returns: 0 = error, 1 = ok to use # bit isFloatingValue(in char[] s) # { # char c; # int len = s.length; # int periods = 0; # # for (int i = 0; i < len; i++) # { # c = s[i]; # # // Set the following characters to lowercase. # if (c == 'E' || c == 'I' || c == 'F') # { # s[i] = c + (cast(char)'a' - 'A'); # c = s[i]; # }
Why change to lower case? If atof needs lower case then I'd say only accept lower case strings.# # if (c >= '0' && c <= '9') # continue; # else if (((c == '-') && (i != len - 1)) && len != 1) # continue; # else if (((c == '+') && (i != len - 1)) && len != 1) # continue; # else if (((c == 'e') && (i != len - 1)) && len != 1) # continue; # else if (c == '.' && periods <= 2 && len != 1) # { # periods++; # continue; # } # else if (((c == 'i') && (i == len - 1)) && len != 1) # continue; # else if (((c == 'f') && (i == len - 1)) && len != 1 ) # continue; # else if (((c == 'L') && (i == len - 1)) && len != 1) # continue; # else # return 0; # } # # return 1; # } # # // When "nan" or "nani" just return them. # if (w == "nan" || w == "nani") # { # s1 = w; # s2 = "0e+0"; # return 1; # } # # // Split the original string out into two strings. # for (int i = 1; i < len; i++) # if ((w[i - 1] != 'e' && w[i - 1] != 'E') && w[i] == '+') # { # w[i] = '^'; # a = split(w, "^"); # break; # } # # // Handle the case when there's only a single value # // to work with, and set the other string to zero. # if (a.length == 0) # a = split(w ~ "^0e+0", "^");
Why use split here? Don't you know exactly where split will actually split?# # // Check the first string. # if (isFloatingValue(a[0])) # s1 = a[0].dup; # else # goto Lerr; # # // Check the second string. # if (isFloatingValue(a[1])) # s2 = a[1].dup; # else # goto Lerr; # # // String is good enough to pass # // into the atof() function. :) # return 1; # # Lerr: # // Display the original string in the error message. # conv_error("\"" ~ s ~ "\""); # return 0; # }
Apr 22 2005
In article <d4b13j$2iaj$1 digitaldaemon.com>, Ben Hinkle says...Some comments about getFloatStrings. I also looked at the definition of atof in std.string. It calls strtold and throws away the end ptr. You might want to directly call strtold and use the end ptr instead of calling atof. Or, since atof calls toStringz, you might want to manage that better, too, since toStringz can (and probably will) dup strings.
Ben many thanks for all your advise! I've made the changes in your suggestions, and have hopefully answered all your questions in my newest post for a final review. Post can be found here: digitalmars.D/22358 I hope you'll look over the newest version, and make a few comments. Thanks again for you help, 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
Apr 23 2005









"TechnoZeus" <TechnoZeus PeoplePC.com> 