View previous topic :: View next topic
|
Author |
Message |
JOSUEGENTIL
New User
Joined: 05 May 2016 Posts: 1 Location: BRAZIL
|
|
|
|
In a COBOL ENTERPRISE program, using COMP-2 and decimal fields, I´m having problem using the conditional IF field-comp2 EQUAL 100:
CP-1 USAGE COMP-2 VALUE 99.99.
CP-2 USAGE COMP-2 VALUE 00.01.
CP-SUM USAGE COMP-2 VALUE 0.
CP-SUM-DEC PIC S9(003)V(006) VALUE 0.
...
ADD CP-1 TO CP-SUM
ADD CP-2 TO CP-SUM
IF CP-SUM EQUAL 100
...
ELSE
...
Altough the sum of 99.99 + 00.01 gives 100 as a result, the ELSE is being applied. If I do the same replacint CP-SUM for CP-SUM-DEC, then the IF statement is correctly applied.
Can anyone help me to understand why the comparison EQUAL works for a decimal field but not for a comp-2, in this case?
Thanks in advane. |
|
Back to top |
|
 |
Robert Sample
Global Moderator

Joined: 06 Jun 2008 Posts: 8700 Location: Dubuque, Iowa, USA
|
|
|
|
COMP-2 variables are floating point; it would be rare indeed for them to be EXACTLY any particular value. When I ran the equivalent to your code:
Code: |
77 CP-1 USAGE COMP-2.
77 CP-2 USAGE COMP-2.
77 CP-SUM USAGE COMP-2 VALUE 0.
77 CP-SUM-DEC PIC S9(003)V9(006) VALUE 0.
*
PROCEDURE DIVISION.
1000-START.
MOVE 99.99 TO CP-1.
MOVE 0.01 TO CP-2.
ADD CP-1 TO CP-SUM.
ADD CP-2 TO CP-SUM.
DISPLAY '>' CP-SUM '<'. |
I got results of:
Code: |
> .99999999999999996E 02< |
Which can be explained as the way COBOL handles intermediate precision for floating point values.
Also, when you post code use the CODE tag for readability. And post working code, not something you cobbled together for this web site. I compiled your code under Enterprise COBOL 5.1.1, and I got 3 errors in the compile: CP-1 and CP-2 VALUE clauses were not valid, and your use of a replication factor in CP-SUM-DEC is not valid (you did NOT put V9(006) which is what COBOL expects -- V(006) as you posted means you want six implied decimal points). |
|
Back to top |
|
 |
sergeyken
Senior Member

Joined: 29 Apr 2008 Posts: 2209 Location: USA
|
|
|
|
JOSUEGENTIL wrote: |
In a COBOL ENTERPRISE program, using COMP-2 and decimal fields, I´m having problem using the conditional IF field-comp2 EQUAL 100:
CP-1 USAGE COMP-2 VALUE 99.99.
CP-2 USAGE COMP-2 VALUE 00.01.
CP-SUM USAGE COMP-2 VALUE 0.
CP-SUM-DEC PIC S9(003)V(006) VALUE 0.
...
ADD CP-1 TO CP-SUM
ADD CP-2 TO CP-SUM
IF CP-SUM EQUAL 100
...
ELSE
...
Although the sum of 99.99 + 00.01 gives 100 as a result, the ELSE is being applied. If I do the same replacing CP-SUM for CP-SUM-DEC, then the IF statement is correctly applied.
Can anyone help me to understand why the comparison EQUAL works for a decimal field but not for a comp-2, in this case?
Thanks in advance. |
Obvious solution: before posting this question on the forum, it is a good idea just to print the actual value of CP-SUM, isn't it?
Floating point in mainframe is handled as binary fixed value, and binary power of the number. This obviously may cause rounding surprises. To avoid this, use any decimal form, like COMP-3, etc. |
|
Back to top |
|
 |
sergeyken
Senior Member

Joined: 29 Apr 2008 Posts: 2209 Location: USA
|
|
|
|
AFAIU, the decimal 99.99 is represented in hex as X'63E6666666666666', with appropriate exponent.
The decimal 0.01 is represented as (normalized) X'10000000000000', with different exponent.
In order to sum two values they are shifted to corresponding binary point position, to make both exponents equal:
Code: |
X'63E6666666666666'
+X'0001000000000000'
=X'63E7666666666666'
|
this is equivalent in decimal: 99. + something below 1.0, while the decimal 100.00 must be represented as X'6400000000000000'
(I may be wrong in details of binary conversion, but the idea is exactly as shown) |
|
Back to top |
|
 |
steve-myers
Active Member
Joined: 30 Nov 2013 Posts: 917 Location: The Universe
|
|
|
|
Sergeyken is correct, though the hex values he shows are incorrect.
Back in the 1960s when I started this trade I did Fortran, on a different platform than S/360, and the fact that conversion of decimal fractions to binary floating point was not always "correct," so floating point comparison was not always "correct" was drummed into our heads.
I transformed the topic starter's program to Assembler, though I was not so foolish to try the comparison. and got this.
Code: |
000000 00000 00038 1 FP CSECT
R:F 00000 2 USING *,15
000000 6800 F018 00018 3 LD 0,CPSUM
000004 6A00 F020 00020 4 AD 0,CP1
000008 6A00 F028 00028 5 AD 0,CP2
00000C 6000 F018 00018 6 STD 0,CPSUM
000010 1BFF 7 SR 15,15
000012 07FE 8 BR 14
000014 00000000
000018 0000000000000000 9 CPSUM DC D'0'
000020 4263FD70A3D70A3D 10 CP1 DC D'99.99'
000028 3F28F5C28F5C28F6 11 CP2 DC D'0.01'
000030 4264000000000000 12 CP100 DC D'100'
000000 13 END FP |
Now I have observed HLASM's floating point conversion often runs 1 bit higher than most compiler's conversion so I cannot confidently state the hex values for CP1 and CP2 here are "correct" but it does illustrate the problem.
I did run this, and got this -
Code: |
l (cp1 cp2 cp100 cpsum
CP1 +.99989999999999998 E+ 2 00000000
CP2 +.10000000000000000 E- 1 00000000
CP100 +.100 E+ 3 00000000
CPSUM +.99999999999999996 E+ 2 00000000
TEST
l (cp1 cp2 cp100 cpsum) x
CP1 00000000
+0 4263FD70 A3D70A3D
CP2 00000000
+0 3F28F5C2 8F5C28F6
CP100 00000000
+0 42640000 00000000
CPSUM 00000000
+0 4263FFFF FFFFFFFF |
|
|
Back to top |
|
 |
steve-myers
Active Member
Joined: 30 Nov 2013 Posts: 917 Location: The Universe
|
|
|
|
For what it's worth, I did CP1 + CP2 like the hardware does it. First, it transforms CP2 to 4200028F5C28F5C2 so the exponents (the 42) are equal, and then adds the fractions in the usual way. Notice that the shift of CP2 discards bits; there is no rounding here.
Had this arithmetic been done with binary (IEEE) floating point there would be rounding in the shift, so there is a better chance that CP1 + CP2 would have resulted in 100.
I converted the program to run binary floating point, and it turned out my theory was correct.
Code: |
Loc Object Code Addr1 Addr2 Stmt Source Statement
000000 00000 00038 1 FP CSECT
R:F 00000 2 USING *,15
000000 6800 F018 00018 3 LD 0,CPSUM
000004 ED00 F020 001A 00020 4 ADB 0,CP1
00000A ED00 F028 001A 00028 5 ADB 0,CP2
000010 6000 F018 00018 6 STD 0,CPSUM
000014 1BFF 7 SR 15,15
000016 07FE 8 BR 14
000018 0000000000000000 9 CPSUM DC DB'0'
000020 4058FF5C28F5C28F 10 CP1 DC DB'99.99'
000028 3F847AE147AE147B 11 CP2 DC DB'0.01'
000030 4059000000000000 12 CP100 DC DB'100'
000000 13 END FP |
Code: |
l (cp1 cp2 cpsum cp100) x
CP1
+0 4058FF5C 28F5C28F
CP2
+0 3F847AE1 47AE147B
CPSUM
+0 40590000 00000000
CP100
+0 40590000 00000000 |
|
|
Back to top |
|
 |
sergeyken
Senior Member

Joined: 29 Apr 2008 Posts: 2209 Location: USA
|
|
|
|
steve-myers wrote: |
I converted the program to run binary floating point, and it turned out my theory was correct. |
Good investigation!
Kindly, clarify for myself the idea of enhanced floating point formats, and rounding rules.
It is obvious how +100.00 in D format is represented as X'4264000000000000'
But it looks like +100.00 in DB format must be X'4019000000000000' (as shifted two bits right, with exponent reduced by 2)
Why it is actually X'4059000000000000'?
Where this single extra bit - X'0040000000000000' - comes from? |
|
Back to top |
|
 |
steve-myers
Active Member
Joined: 30 Nov 2013 Posts: 917 Location: The Universe
|
|
|
|
z/Architecture supports two (actually three) floating point formats.- The original System/360 floating point. This was actually pretty lousy. I've always thought it was added on very late in the game when someone, my theory has always been in marketing, realized, "My God, there's no floating point! How are we gonna sell this to the 709x and 704x crowd?" So the hardware people very hurriedly devised the cheapest possible (to implement) floating point. I remember analyzing this standard in 1966 and realized how lousy it was. In fact it was worse than my 1966 analysis revealed! One conclusion I did reach was in the real world you had to do everything in double precision because there were so few bits in single precision. It was so bad IBM was forced to spend I couldn't guess how many millions fixing the worse problems in the machines in the field in 1968.
- "Binary" floating point. This is an implementation of the IEEE floating point standard which was formalized from the 8087 Intel coprocessing chip which now exists in every x86 chip Intel makes.
- Decimal floating point. I know very little about this other than it exists.
There is a pretty decent discussion, far better than I can do, here. |
|
Back to top |
|
 |
|
|