|
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 +---
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.