Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Data conversion in RPG/IV

71 views
Skip to first unread message

Jürgen Schatzl

unread,
Jul 19, 2000, 3:00:00 AM7/19/00
to
Hi,

am I missing something, or is there really no build in function for
converting alphanumeric values to numeric ones ?

If so, how do you cope with it ?


TIA

Juergen

--
Juergen Schatzl AS/400, single malts
sch...@attglobal.net

Worley Barry

unread,
Jul 19, 2000, 3:00:00 AM7/19/00
to
On Wed, 19 Jul 2000 18:22:25 +0200, Jürgen Schatzl wrote:

>Hi,
>
>am I missing something, or is there really no build in function for
>converting alphanumeric values to numeric ones ?
>
>If so, how do you cope with it ?
>

MOVE operand.

Regards Worley


Barbara Morris

unread,
Jul 19, 2000, 3:00:00 AM7/19/00
to
Worley Barry wrote:
> >
> >am I missing something, or is there really no build in function for
> >converting alphanumeric values to numeric ones ?
> >
> >If so, how do you cope with it ?
> >
> MOVE operand.

MOVE is ok for simple values like '12345', but it won't handle
'-12.34'. For that, it's best to write your own parsing routine. I've
written one that anyone is free to use or modify. It handles strings
representing numbers with up to 21 integer places and up to 9 decimal
places. It handles input in many different forms (see comments). It
doesn't check for invalid input.

By the way, people may recommend using the C runtime function atof:
EVAL(H) value = atof(string)
but that does not always return the correct result.

(Sorry for the length of this post)

Barbara Morris

<-----* prototype for /COPY file start here ----->

*---------------------------------------------------------
* getNum - procedure to read a number from a string
* and return a 30p 9 value
* Parameters:
* I: string - character value of number
* I:(opt) decComma - decimal point and digit separator
* I:(opt) currency - currency symbol for monetary amounts
* Returns: packed(30,9)
*
* Parameter details:
* string: the string may have
* - blanks anywhere
* - sign anywhere
* accepted signs are: + - cr CR ()
* (see examples below)
* - digit separators anywhere
* - currency symbol anywhere
* decComma: if not passed, this defaults to
* decimal point = '.'
* digit separator = ','
* currency: if not passed, defaults to ' '
*
* Examples of input and output (x means parm not passed):
*
* string | dec | sep | cursym | result
* ---------------+-----+-----+--------+------------
* 123 | x | x | x | 123
* +123 | x | x | x | 123
* 123+ | x | x | x | 123
* -123 | x | x | x | -123
* 123- | x | x | x | -123
* (123) | x | x | x | -123
* 12,3 | , | . | x | 12.3
* 12.3 | x | x | x | 12.3
* 1,234,567.3 | x | x | x | 1234567.3
* $1,234,567.3 | . | , | $ | 1234567.3
* $1.234.567,3 | , | . | $ | 1234567.3
* 123.45CR | x | x | x | -123.45
*
* Author: Barbara Morris, IBM Toronto Lab
* Date: March, 2000
*---------------------------------------------------------
D getNum pr 30p 9
D string 100a const varying
D decComma 2a const options(*nopass)
D currency 1a const options(*nopass)

<-----* prototype for /COPY file end here ----->

<-----* test program start here----->

* Copy prototype for procedure getNum
D/COPY GETNUM_P

D res s like(getNum)
D msg s 52a

C *entry plist
C parm p 32
C parm dc 2
C parm c 1

C select
C when %parms = 1
C eval res = getNum(p)
C when %parms = 2
C eval res = getNum(p : dc)
C when %parms = 3
C eval res = getNum(p : dc : c)
C endsl
C eval msg = '<' + %char(res) + '>'
C msg dsply

C return

<-----* test program end here----->

<-----* module GETNUM start here ----->

H NOMAIN

* Copy prototype for procedure getNum
D/COPY GETNUM_P

p getNum b
D getNum pi 30p 9
D string 100a const varying
D decComma 2a const options(*nopass)
D currency 1a const options(*nopass)

* defaults for optional parameters
D decPoint s 1a inz('.')
D comma s 1a inz(',')
D cursym s 1a inz(' ')
* structure for building result
D ds
D result 30s 9 inz(0)
D resChars 30a overlay(result)
* variables for gathering digit information
* pNumPart points to the area currently being gathered
* (the integer part or the decimal part)
D pNumPart s *
D numPart s 30a varying based(pNumPart)
D intPart s 30a varying inz('')
D decPart s 30a varying inz('')
* other variables
D intStart s 10i 0
D decStart s 10i 0
D sign s 1a inz('+')
D i s 10i 0
D len s 10i 0
D c s 1a

* override defaults if optional parameters were passed
C if %parms > 1
C eval decPoint = %subst(decComma : 1 : 1)
C eval comma = %subst(decComma : 2 :1)
C endif

C if %parms > 2
C eval cursym = currency
C endif

* initialization
C eval len = %len(string)
* begin reading the integer part
C eval pNumPart = %addr(intPart)

* loop through characters
C do len i
C eval c = %subst(string : i : 1)

C select
* ignore blanks, digit separator, currency symbol
C when c = comma or c = *blank or c = cursym
C iter
* decimal point: switch to reading the decimal part
C when c = decPoint
C eval pNumPart = %addr(decPart)
C iter
* sign: remember the most recent sign
C when c = '+' or c = '-'
C eval sign = c
C iter
* more signs: cr, CR, () are all negative signs
C when c = 'C' or c = 'R' or
C c = 'c' or c = 'r' or
C c = '(' or c = ')'
C eval sign = '-'
C iter
* a digit: add it to the current build area
C other
C eval numPart = numPart + c

C endsl
C enddo

* copy the digit strings into the correct positions in the
* zoned variable, using the character overlay
C eval decStart = %len(result) -
%decPos(result)
C + 1
C eval intStart = decStart - %len(intPart)
C eval %subst(resChars
C : intStart
C : %len(intPart))
C = intPart
C eval %subst(resChars
C : decStart
C : %len(decPart))
C = decPart
* if the sign is negative, return a negative value
C if sign = '-'
C return - result
* otherwise, return the positive value
C else
C return result
C endif
p e

<-----* module GETNUM end here ----->

Jürgen Schatzl

unread,
Jul 20, 2000, 3:00:00 AM7/20/00
to
Hi Barbara,

bmo...@ca.ibm.com (Barbara Morris) wrote in
<39764DD9...@ca.ibm.com>:

>By the way, people may recommend using the C runtime function atof:
> EVAL(H) value = atof(string)
>but that does not always return the correct result.
>

Thanks for the code. One more question: when and why does atof not return
correct values ?


Juergen


--
Juergen Schatzl
AS/400 Programmer

The opinions expressed are mine, not those of
BRAIN Filderstadt or any of its affiliates

Barbara Morris

unread,
Jul 20, 2000, 3:00:00 AM7/20/00
to
atof uses binary floating point. Some decimal numbers cannot be
represented exactly in binary, so the floating point version of the
number is an approximation. See the end of this post for an example.

Usually rounding takes care of the error, but not always. Another
problem is the precision. Floating point numbers have a precision of
around 16 or 17 digits. The procedure I posted has a precision
limitation too (maximum of 21 integer places, 9 decimal places). A
better (but less pleasant to call) version of the procedure would not
return the value, but instead have an additional 3 parameters: the
address of a zoned variable, along with the number of digits and decimal
points.

By the way, the function 'atoi' is more reliable but caution must be
used there too: atoi only handles values as large as an integer can
hold (around 2,000,000,000). If you try to read an 11 digit number
using atoi, you will get incorrect results.

Barbara Morris

Try this code:
D num s 8f inz(9)
C do 10
C num dsply
C eval num = num / 10
C enddo

DSPLY +9.000000000000000E+000
DSPLY +9.000000000000000E-001
DSPLY +8.999999999999998E-002
DSPLY +8.999999999999996E-003
DSPLY +8.999999999999996E-004
DSPLY +8.999999999999994E-005
DSPLY +8.999999999999992E-006
DSPLY +8.999999999999991E-007
DSPLY +8.999999999999991E-008

"Jürgen Schatzl" wrote:
>
> Hi Barbara,
>
> bmo...@ca.ibm.com (Barbara Morris) wrote in
> <39764DD9...@ca.ibm.com>:
>

> >By the way, people may recommend using the C runtime function atof:
> > EVAL(H) value = atof(string)
> >but that does not always return the correct result.
> >

Jürgen Schatzl

unread,
Jul 21, 2000, 3:00:00 AM7/21/00
to
Hi Barbara,

thanks again for your valuable information.

0 new messages