PDA

View Full Version : Rechenproblem in RPG



jo400
17-05-04, 12:57
Hallo Forum,

uns ist ein Problem beim Rechnen in RPG aufgefallen; vielleicht weiß einer von euch, woran es liegt.

RPG-Quelltext:

DFELD1 S 11 2 INZ
DFELD2 S 11 2 INZ
DERGEBNIS S 6 2 INZ
*
C EVAL FELD1 = 360262,60
C EVAL FELD2 = 442040,00
*
C EVAL ERGEBNIS = FELD1 /
C (FELD2 / 100)
C ERGEBNIS DSPLY
*
C EVAL ERGEBNIS = (FELD1 /
C FELD2) * 100
C ERGEBNIS DSPLY
*
C EVAL *INLR = *ON

Im ersten Fall ist das Ergebnis bei uns 81,0 und im zweiten Fall ist das Ergebnis 81,5.
Das korrekte Ergebnis ist 81,5.

Was machen wir falsch?

Vielen Dank für eure Unterstützung.

Jo

PS: Wir haben OS/400 V5R2.

Fuerchau
17-05-04, 13:06
Naja, eigentlich gar nichts. Das Problem ist, dass RPG bei Zwischenergebnissen die Feldausprägung der Felder übernimmt und nicht rundet !

Sollen Zwischenergebnisse in größerer Genauigkeit erfolgen, muss man leider wie früher zu Hilfsfeldern greifen.

jo400
17-05-04, 13:18
Hallo Fuerchau,

danke für die schnelle Antwort.

Aber wenn ich doch 442040,00 durch 100 teile, bekomme ich 4420,40 raus; das passt in das ursprüngliche Feld und es muss auch nichts gerundet werden; es funktioniert auch dann nicht, wenn wir größere Felder (mit mehr Nachkommastellen) verwenden. Gibt es eventuell ein RPG-Problem bei der Abarbeitung der EVAL-Anweisung?

Jo

Fuerchau
17-05-04, 13:37
Das Problem hier ist, dass die Zahl "100" keine Nachkomma hat, das Zwischenergebnis damit auch nicht, da das letzte Feld (in diesem Fall Konstante) genommen wird !

Statt " / 100" kann auch " * 0.01" verwendet werden (Mult ist übrigens immer schneller als Div) um die Anzahl NK zu erweitern.

TARASIK
17-05-04, 13:47
Hallo Jo,
bei der IBM gibt es dies dazu:

http://www-912.ibm.com/a_dir/as4ptf.nsf/b1cd508fa850028686256c2300702726/ebbde805702949ba86256e3c005824a7?OpenDocument&Highlight=0,eval,r520

jo400
18-05-04, 09:56
Hallo Furchau, hallo Tarasik,

vielen Dank für eure Antworten.

@Fuerchau:
Jetzt ist es mir klar; wenn ich die Konstante 100,00 verwende, dann hat es funktioniert.

@Tarasik:
Ich werde mir das PTF besorgen und dann testen.

Nochmals vielen Dank.

Jo

Fuerchau
18-05-04, 10:10
Das PTF hat mit diesem "Problem" überhaupt nichts zu tun sondern betrifft die reine Fließkomma-Arithmetik.
Im ILE-RPG-Reference-Handbuch wird ausführlich die Berechnung von Zwischenergebnissen erklärt.
Für kaufmännische Berechnungen stört mich am meisten die fehlende Rundung der Zwischenergebnisse.


Precision Rules for Numeric Operations
Unlike the fixed-form operation codes where you must always specify the result of
each individual operation, RPG must determine the format and precision of the
result of each operation within an expression.
If an operation has a result of format float, integer, or unsigned the precision is the
maximum size for that format. Integer and unsigned operations produce 4-byte
values and float operations produce 8-byte values.
However, if the operation has a packed-decimal, zoned decimal, or binary format,
the precision of the result depends on the precisions of the operands.
It is important to be aware of the precision rules for decimal operations since even
a relatively simple expression may have a result that may not be what you expect.
For example, if the two operands of a multiplication are large enough, the result of
the multiplication will have zero decimal places. If you are multiplying two 20
digit numbers, ideally you would need a 40 digit result to hold all possible results
of the multiplication. However, since RPG supports numeric values only up to 31
digits, the result is adjusted to 31 digits. In this case, as many as 10 decimal digits
are dropped from the result.
There are two sets of precision rules that you can use to control the sizes of
intermediate values:
1. The default rules give you intermediate results that are as large as possible in
order to minimize the possibility of numeric overflow. Unfortunately, in certain
cases, this may yield results with zero decimal places if the result is very large.
2. The ″Result Decimal Positions″ precision rule works the same as the default
rule except that if the statement involves an assignment to a numeric variable
or a conversion to a specific decimal precision, the number of decimal positions
of any intermediate result is never reduced below the desired result decimal
places.
In practice, you don’t have to worry about the exact precisions if you examine
the compile listing when coding numeric expressions. A diagnostic message
indicates that decimal positions are being dropped in an intermediate result. If
there is an assignment involved in the expression, you can ensure that the
decimal positions are kept by using the ″Result Decimal Positions″ precision
rule for the statement by coding operation code extender (R).
If the ″Result Decimal Position″ precision rule cannot be used (say, in a
relational expression), built-in function %DEC can be used to convert the result
of a sub-expression to a smaller precision which may prevent the decimal
positions from being lost.
Using the Default Precision Rules
Using the default precision rule, the precision of a decimal intermediate in an
expression is computed to minimize the possibility of numeric overflow. However,
if the expression involves several operations on large decimal numbers, the
intermediates may end up with zero decimal positions. (Especially, if the
expression has two or more nested divisions.) This may not be what the
programmer expects, especially in an assignment.
When determining the precision of a decimal intermediate, two steps occur:
1. The desired or ″natural″ precision of the result is computed.
Precision Rules for Numeric Operations
2. If the natural precision is greater than 31 digits, the precision is adjusted to fit
in 31 digits. This normally involves first reducing the number of decimal
positions, and then if necessary, reducing the total number of digits of the
intermediate.
This behaviour is the default and can be specified for an entire module (using
control specification keyword EXPROPTS(*MAXDIGITS) or for single free-form
expressions (using operation code extender M).
Precision of Intermediate Results
Table 52 describes the default precision rules in more detail.
Table 52. Precision of Intermediate Results
Operation Result Precision
Note: The following operations produce a numeric result. L1 and L2 are the number of
digits of the two operands. Lr is the number of digits of the result. D1 and D2 are the
number of decimal places of the two operands. Dr is the number of decimal places of the
result. T is a temporary value.
N1+N2 T=min (max (L1-D1, L2-D2)+1, 31)
Dr=min (max (D1,D2), 31-t)
Lr=t+Dr
N1-N2 T=min (max (L1-D1, L2-D2)+1, 31)
Dr=min (max (D1,D2), 31-t)
Lr=t+Dr
N1*N2 Lr=min (L1+L2, 31)
Dr=min (D1+D2, 31-min ((L1-D1)+(L2-D2), 31))
N1/N2 Lr=31
Dr=max (31-((L1-D1)+D2), 0)
N1**N2 Double float
Note: The following operations produce a character result. Ln represents the length of the
operand in number of characters.
C1+C2 Lr=min(L1+L2,65535)
Note: The following operations produce a DBCS result. Ln represents the length of the
operand in number of DBCS characters.
D1+D2 Lr=min(L1+L2,16383)
Note: The following operations produce a result of type character with subtype indicator.
The result is always an indicator value (1 character).
V1=V2 1 (indicator)
V1>=V2 1 (indicator)
V1>V2 1 (indicator)
V1<=V2 1 (indicator)
V1<V2 1 (indicator)
V1<>V2 1 (indicator)
V1 AND V2 1 (indicator)
V1 OR V2 1 (indicator)
Precision Rules for Numeric Operations
Chapter 21. Expressions 429
Example of Default Precision Rules
This example shows how the default precision rules work.
When the above Calculation specification is processed, the resulting value assigned
to FLD1 will have a precision of zero decimals, not the three decimals expected.
The reason is that when it gets to the last evaluation (4 in the above example),
the number to which the factor is scaled is negative. To see why, look at how the
expression is evaluated.
1 Evaluate FLD3/100
Rules:
Lr = 31
Dr = max(31-((L1-D1)+D2),0)
= max(31-((5-2)+0),0)
= max(31-3,0)
= 28
2 Evaluate (Result of 1 * FLD4)
Rules:
Lr = min(L1+L2,31)
= min(31+9,31)
= 31
Dr = min(D1+D2,31-min((L1-D1)+(L2-D2),31))
= min(28+4,31-min((30-28)+(9-4),31))
= min(32,31-min(4+5,31)
= min(32,22)
= 22
3 Evaluate (Result of 2 + FLD5)
Rules:
T = min(max(L1-D1,L2-D2)+1,31)
= min(max(31-22,9-4)+1,31)
= min(max(9,5)+1,31)
= min(10,30)
= 10
Dr = min(max(D1,D2),31-T)
= min(max(22,4),31-10)
= min(22,21)
= 21
Lr = T + Dr
= 10 + 21 = 31
4 Evaluate FLD2/Result of 3
Rules:
DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++
D FLD1 S 15P 4
D FLD2 S 15P 2
D FLD3 S 5P 2
D FLD4 S 9P 4
D FLD5 S 9P 4
CL0N01Factor1+++++++Opcode(E)+Extended-factor2+++++++++++++++++++++++++++
C EVAL FLD1 = FLD2/(((FLD3/100)*FLD4)+FLD5)
( 1 )
( 2 )
( 3 )
( 4 )
Figure 160. Precision of Intermediate Results
Precision Rules for Numeric Operations
Lr = 31
Dr = max(31-((L1-D1)+D2),0)
= max(31-((15-2)+ 21),0)
= max(31-(13+21),0)
= max(-3,0) **** NEGATIVE NUMBER TO WHICH FACTOR IS SCALED ****
= 0
To avoid this problem, you can change the above expression so that the first
evaluation is a multiplication rather than a division, that is, FLD3 * 0.01 or use the
%DEC built-in function to set the sub-expression FLD3/100: %DEC(FLD3/100 : 15 :
4) or use operation extender (R) to ensure that the number of decimal positions
never falls below 4.
Using the ″Result Decimal Position″ Precision Rules
The ″Result Decimal Position″ precision rule means that the precision of a decimal
intermediate will be computed such that the number of decimal places will never
be reduced smaller than the number of decimal positions of the result of the
assignment. This is specified by:
1. EXPROPTS(*RESDECPOS) on the Control Specification. Use this to specify
this behaviour for an entire module.
2. Operation code extender R specified for a free-form operation.
Result Decimal Position rules apply in the following circumstances:
1. Result Decimal Position precision rules apply only to packed decimal
intermediate results. This behaviour does not apply to the intermediate results
of operations that have integer, unsigned, or float results.
2. Result Decimal Position precision rules apply only where there is an
assignment (either explicit or implicit) to a decimal target (packed, zoned, or
binary). This can occur in the following situations:
a. For an EVAL statement, the minimum decimal places is given by the
decimal positions of the target of the assignment and applies to the
expression on the right-hand side of the assignment. If half-adjust also
applies to the statement, one extra digit is added to the minimum decimal
positions (provided that the minimum is less than 31).
b. For a RETURN statement, the minimum decimal places is given by the
decimal positions of the return value defined on the PI specification for the
procedure. If half-adjust also applies to the statement, one extra digit is
added to the minimum decimal positions (provided that the minimum is
less than 31).
c. For a VALUE or CONST parameter, the minimum decimal positions is
given by the decimal positions of the formal parameter (specified on the
procedure prototype) and applies to the expression specified as the passed
parameter.
d. For built-in function %DEC and %DECH with explicit length and decimal
positions specified, the minimum decimal positions is given by the third
parameter of the built-in function and applies to the expression specified as
the first parameter.
The minimum number of decimal positions applies to the entire sub-expression
unless overridden by another of the above operations. If half-adjust is specified
(either as the H operation code extender, or by built-in function %DECH), the
number of decimal positions of the intermediate result is never reduced below
N+1, where N is the number of decimal positions of the result.
Precision Rules for Numeric Operations
Chapter 21. Expressions 431
3. The Result Decimal Position rules do not normally apply to conditional
expressions since there is no corresponding result. (If the comparisons must be
performed to a particular precision, then %DEC or %DECH must be used on
the two arguments.)
On the other hand, if the conditional expression is embedded within an
expression for which the minimum decimal positions are given (using one of
the above techniques), then the Result Decimal Positions rules do apply.
Example of ″Result Decimal Position″ Precision Rules
The following examples illustrate the ″Result Decimal Position″ precision rules:
*..1....+....2....+....3....+....4....+....5....+. ...6....+....7...+....
* This example shows the precision of the intermediate values
* using the two precision rules.
D p1 s 13p 2
D p2 s 13p 2
D p3 s 13p 2
D p4 s 15p 9
D s1 s 13s 2
D s2 s 13s 2
D i1 s 10i 0
D f1 s 8f
D proc pr 8p 3
D parm1 20p 5 value
* In the following examples, for each sub-expression,
* two precisions are shown. First, the natural precision,
* and then the adjusted precision.
* Example 1:
/FREE
eval p1 = p1 * p2 * p3;
// p1*p2 -> P(26,4); P(26,4)
// p1*p2*p3 -> P(39,6); P(31,0) (decimal positions are truncated)
eval(r) p1 = p1 * p2 * p3;
// p1*p2 -> P(26,4); P(26,4)
// p1*p2*p3 -> P(39,6); P(31,2) (decimal positions do not drop
// below target decimal positions)
eval(rh)p1 = p1 * p2 * p3;
// p1*p2 -> P(26,4); P(26,5)
// p1*p2*p3 -> P(39,6); P(31,3) (decimal positions do not drop
// below target decimals + 1)
// Example 2:
eval p4 = p1 * p2 * proc (s1*s2*p4);
// p1*p2 -> P(26,4); P(26,4)
// s1*s2 -> P(26,4); P(26,4)
// s1*s2*p4 -> P(41,13); P(31,3) (decimal positions are truncated)
// p1*p2*proc() -> P(34,7); P(31,4) (decimal positions are truncated)
eval(r) p4 = p1 * p2 * proc (s1*s2*p4);
// p1*p2 -> P(26,4); P(26,4)
// s1*s2 -> P(26,4); P(26,4)
// s1*s2*p4 -> P(41,13); P(31,5)
// p1*p2*proc() -> P(34,7); P(31,7) (we keep all decimals since we are
// already below target decimals)
/END-FREE

KM
01-06-04, 14:59
Hallo Jo,

warum benutzt Du nicht einfach den EVAL(R) ? Dieser rechnet richtig, egal wieviele Nachkommastellen vorhanden sind.

Gruß,
KM

BenderD
01-06-04, 15:14
Hallo jo400,


Hallo Forum,

Was machen wir falsch?

Jo

PS: Wir haben OS/400 V5R2.

Ihr verwendet Literale (100) beim Rechnen, das gibt mit allen Compilern der Welt Randprobleme.

mfg

Dieter Bender

Fuerchau
01-06-04, 20:34
Ausgenommen Sprachen, die den Feldtyp "Dezimal" nicht kennen und immer nur mit Float/Double rechnen. Hier sind die Probleme mit den Nachkommastellen viel gravierenden:
Dezimal: 3 * 3.33 = 9.99
Double: 3 * 3.33 = 10.000000000001

Und dann wundert man sich immer warum rechnet der nur so komisch ?!