At the risk of inflicting more physical abuse on a deceased
equine, I'd like to offer one more consideration on choosing
a method for converting character to numeric - performance.
Out of curiosity, I did a comparison between a number of
different methods for character to numeric conversion:
1) C run-time function "atof". We know this suffers from
accuracy problems with numbers bigger than about 15 digits,
but I included it anyways as a benchmark.
2) The "#CtoN" function posted on the web page
<http://www.bvstools.com/download.html>, but with the
correction posted here by Barbara.
3) Barbara's "GetNum" procedure.
4) A simplified version of Barbara's GetNum procedure.
(called "CharToNum")
Here are the results averaged from 5 runs on a lightly
loaded system. Each procedure is called 100000 times in a
loop to convert the string '123456789.12345'. Here are the
results:
CharToNum: 3983 ms (fastest)
atof: 5568 ms
GetNum: 5968 ms
#CtoN: 9580 ms (slowest)
Here are the results from converting the string '1234':
CharToNum: 1710 ms (fastest)
atof: 2419 ms
#CtoN: 3329 ms
GetNum: 4943 ms (slowest)
Here are the results from converting the string '1':
CharToNum: 1068 ms (fastest)
#CtoN: 1974 ms
atof: 2683 ms (slower than for '1234'!)
GetNum: 4485 ms (slowest)
For smaller numbers (which arguably could be more common
in practice than big numbers), the standings change
considerably, and #CtoN moves up two places for the one
digit number.
Although "GetNum" and "CharToNum" use basically the same
method, "GetNum" is much more robust and can handle a wide
variety of different formats and sign characters. These
two procedures are interesting in that basically no
arithmetic is involved in the conversion. These procedures
consider character to numeric conversion as a string
manipulation problem.
For completeness, here's the source to the "CharToNum"
procedure. I must warn that the procedure hasn't been
tested fully, but does work with a random selection of
values in the range 0.000000001 to
999999999999999999999.999999999. (Program is in V5R1
syntax, but should be easy to rewrite into V4R4 RPG.)
-------------------------------------------------------------------------------
//----------------------------------------------------------------------//
// Module: CHARTONUM
//
//
//
// Entries:
//
//
//
// CharToNum -- convert character string to packed numeric
//
//
//
//----------------------------------------------------------------------//
H nomain
D CharToNum PR 30P 9
D Str 50A VARYING CONST
//----------------------------------------------------------------------//
// Exported procedure: CharToNum
//
// Purpose: Convert a character string to decimal numeric
//
//----------------------------------------------------------------------//
P CharToNum B export
D CharToNum PI 30P 9
D Str 50A varying const
D negative S N inz(*OFF)
D string DS 30
D decnum 30S 9 inz(0)
D i S 10I 0 inz(1)
D digits S 10I 0 inz(0)
D decpos S 10I 0 inz(0)
D dec S 10I 0 inz(0)
D ch S 1a
D chtemp S 30a varying
/free
// Skip leading blanks (if any)
dow i <= %len(Str) and %subst(Str:i:1) = ' ';
i = i + 1;
enddo;
// Is string all blanks?
if i > %len(Str);
return 0;
endif;
// Is first non-blank char a minus sign?
if %subst(Str:i:1) = '-';
negative = *ON;
i = i + 1;
endif;
// Skip leading zeros (if any)
dow i <= %len(Str) and %subst(Str:i:1) = '0';
i = i + 1;
enddo;
// Is string all zeros and blanks?
if i > %len(Str);
return 0;
endif;
// Loop through digits of string to be converted
dow i <= %len(Str);
ch = %subst(Str:i:1);
if ch = '.';
// We've reached the decimal point - only
// one allowed
if decpos <> 0;
// We've already read a decimal point
leave;
endif;
// Indicate decimal position just after last
// digit read.
decpos = digits + 1;
elseif ch >= '0' and ch <= '9';
// We've read a digit - save it
digits = digits + 1;
chtemp = chtemp + ch;
// Have we read enough digits?
if digits = 30;
leave;
endif;
else;
// Anything other than a digit or decimal point
// ends the number
leave;
endif;
// Advance to the next character
i = i + 1;
enddo;
// Adjust decimal positions
if decpos = 0;
// If no decimal point coded, assume one after all digits
decpos = %len(chtemp) + 1;
else;
// drop excess decimal digits
dec = %len(chtemp) - decpos + 1;
if dec > 9;
%len(chtemp) = %len(chtemp) - (dec - 9);
endif;
endif;
// Scale number appropriately
%subst(string: 23-decpos: %len(chtemp)) = chtemp;
// Set sign of result
if negative;
decnum = - decnum;
endif;
// Return answer
return decnum;
/end-free
P CharToNum E
-------------------------------------------------------------------------
Cheers! Hans
Hans Boldt, ILE RPG Development, IBM Toronto Lab, boldt@ca.ibm.com
+---
| This is the RPG/400 Mailing List!
| To submit a new message, send your mail to RPG400-L@midrange.com.
| To subscribe to this list send email to RPG400-L-SUB@midrange.com.
| To unsubscribe from this list send email to RPG400-L-UNSUB@midrange.com.
| Questions should be directed to the list owner/operator: david@midrange.com
+---