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.

Joined: 06 Jun 2008 Posts: 8569 Location: Dubuque, Iowa, USA

Posted: Wed Nov 08, 2017 11:16 pm

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).

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.

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:

Joined: 30 Nov 2013 Posts: 870 Location: The Universe

Posted: Thu Nov 09, 2017 7:27 am

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

Joined: 30 Nov 2013 Posts: 870 Location: The Universe

Posted: Thu Nov 09, 2017 8:45 am

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.

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?

Joined: 30 Nov 2013 Posts: 870 Location: The Universe

Posted: Fri Nov 10, 2017 6:06 am

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.