I have an unsigned binary-short item that when subtracting/computing a result that would result in a negative answer/result, it is different depending on doing a compute or performing a subtract. And I know you shouldn't do that.
So, my question is which is correct?
The attached program-et does both and displays the result using BIT-OF and an edit data item to display the result.
If you are not familiar with the BIT-OF function, it displays data items from left to right one character at a time. So, the 2-byte binary-short being in little endian will display 8 bits of low order then 8 bits of high order. That is why it displays the value 1 as 0000000100000000 instead of 0000000000000001.
It would be interesting to compare the results (needs another work field) in addition to displaying the individual results.
One appears to be big endian the other little endian.
Can you dispense with the "C" definition ( BINARY-SHORT UNSIGNED)
and use the COBOL definition of "comp." ?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I see now. The display is piecemeal, rather than line-oriented.
But the thought occurs to me that if you COMPUTE the sum of zero minus one, and then store it in an unsigned binary short (presumably a 16 bit integer), the result should be one, since no negative numbers are allowed. Therefore SUBTRACT must take a different path.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is a bug in the generated code for the SUBTRACT statement. Specifically when subtracting from an unsigned binary field...
In this case the generated code should include the "abs" function to return the absolute value.
see the Winmerge screen shot which compares the original generated C code to the modified version I created...
original
(*(unsigned short *)(b_17)) = ((*(unsigned short *)(b_17)) - (*(unsigned short *)(b_17 + 2)));modified (*(unsigned short *)(b_17)) = abs(((*(unsigned short *)(b_17)) - (*(unsigned short *)(b_17 + 2))));
I will check with Simon about a fix for this issue as the error is in the code generation, not the libcob runtime.
ps... Thanks to Michael for finding and reporting this bug....
I would think that an overflow condition code should be raised.
Should it not ?
A COMP-4 definition and a COMP-5 definition might dictate different behaviors
See the screen shot below from a Micro Focus test - both Enterprise and non-mainframe had the same behavior.
His app should abend ?
Using the absolute value is questionable in my opinion
In COBOL when you try to subtract 1 from an unsigned field containing 0, you'll get a size error (also called an overflow condition)
COBOL provides the ON SIZE ERROR clause to handle this situation.
For example:
SUBTRACT 1 FROM NUMBER-FIELD
ON SIZE ERROR
PERFORM ERROR-HANDLING-PARAGRAPH
END-SUBTRACT
Without proper error handling, the program will typically abort with a runtime error. This is different from languages like C where unsigned integer underflow wraps around to the maximum value - that is x'FFFFFFFF'
This strict behavior in COBOL is part of its design philosophy for business applications, where unexpected numerical behaviors could lead to serious financial errors. COBOL prioritizes detecting these conditions rather than allowing silent wraparound.
Correction: The COBOL standard defines that checking for size errors is only enabled if either the SIZE ERROR phrase is used or (since COBOL2002) an applicable >> TURN directive to enable that is used. Otherwise it is undefined.
Before COBOL2002 the result of a SIZE ERROR without that phrase was undefined altogether.
Using ON SIZE ERROR leads to the target field being unchanged.
As all of the EC-SIZE are fatal, checking for them (if no ON SIZE ERROR is specified) without handling the exception would abend the runtime.
I remember from a migration from ACUCOBOL-GT to OpenCOBOL that ACUCOBOL used the absolute value for unsigned result fields and truncated [following the rules for MOVE of an intermediate result to the final result] , while OpenCOBOL used to store zero or kept it unchanged. Using ON SIZE ERROR MOVE 0 TO resultcreated the same behavior for both environments.
Note: COMP-4 + COMP-5 (or the standard binary types) are an extension, so they can have implicit rules (and I'd expect a binary truncation/overflow in most cases).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ralph.
I had done a size error check before submitting the starting post to this thread.
It changes the result of the SUBTRACT verb.
Here is a screen shot.
Notice that it goes from 1 to 0 to 1 to 0 repeatedly/infinity.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2025-02-08
Chuck and I have been analyzing the behavior of "0 - 1" across Micro Focus, Fujitsu, and GnuCOBOL.
3 different compilers - 3 different sets of results.
There is a very simple test case attached.
Try it - it highlight the behavior you are seeing but with displays of the binary data.
Good find
The issue originally discussed relating to COMPUTE vs SUBTRACT might not be an issue after all. When doing a subtract, the use of a GIVING or not changes how SUBTRACT works. The programmers guide (P.G.) documents three different SUBTRACT verbs. Reading VERY INTENTLY one sees that the three variations of SUBTRACT are different in functionality. SUBTRACT A FROM B will give you a different answer than SUBTRACT A FROM B GIVING C or SUBTRACT A FROM B GIVING B with the result being negative.
THAT IS WHEN WORKING WITH BINARY UNSIGNED DATA ITEMS FOR RESULTS.
Without the GIVING option, the function takes place in B. With the GIVING option, neither A nor B are modified, and the result is placed in C. (unless the giving is B.)
My conclusion is (SUBTRACT A FROM B GIVING B) is functionally the same as
(COMPUTE B = B - A) and one should take precautions if storing negative numbers in unsigned data items is likely. That is akin to not allowing dividing by zero.
Attached is a test case showing that GIVING is the way to go. I have tried several data definitions for the results. See the commented-out lines in the code if you are interested.
I have an unsigned binary-short item that when subtracting/computing a result that would result in a negative answer/result, it is different depending on doing a compute or performing a subtract. And I know you shouldn't do that.
So, my question is which is correct?
The attached program-et does both and displays the result using BIT-OF and an edit data item to display the result.
If you are not familiar with the BIT-OF function, it displays data items from left to right one character at a time. So, the 2-byte binary-short being in little endian will display 8 bits of low order then 8 bits of high order. That is why it displays the value 1 as 0000000100000000 instead of 0000000000000001.
Michael :-)
When I compile that program, only the final display appears. Is there some magic required to display at row/column locations?
This is the only result I get:
I expected to get four sets of displays like the above.
It would be interesting to compare the results (needs another work field) in addition to displaying the individual results.
One appears to be big endian the other little endian.
Can you dispense with the "C" definition ( BINARY-SHORT UNSIGNED)
and use the COBOL definition of "comp." ?
I see now. The display is piecemeal, rather than line-oriented.
But the thought occurs to me that if you COMPUTE the sum of zero minus one, and then store it in an unsigned binary short (presumably a 16 bit integer), the result should be one, since no negative numbers are allowed. Therefore SUBTRACT must take a different path.
This is a bug in the generated code for the SUBTRACT statement. Specifically when subtracting from an unsigned binary field...
In this case the generated code should include the "abs" function to return the absolute value.
see the Winmerge screen shot which compares the original generated C code to the modified version I created...
I will check with Simon about a fix for this issue as the error is in the code generation, not the libcob runtime.
ps... Thanks to Michael for finding and reporting this bug....
I would think that an overflow condition code should be raised.
Should it not ?
A COMP-4 definition and a COMP-5 definition might dictate different behaviors
See the screen shot below from a Micro Focus test - both Enterprise and non-mainframe had the same behavior.
His app should abend ?
Using the absolute value is questionable in my opinion
In COBOL when you try to subtract 1 from an unsigned field containing 0, you'll get a size error (also called an overflow condition)
COBOL provides the ON SIZE ERROR clause to handle this situation.
For example:
SUBTRACT 1 FROM NUMBER-FIELD
ON SIZE ERROR
PERFORM ERROR-HANDLING-PARAGRAPH
END-SUBTRACT
Without proper error handling, the program will typically abort with a runtime error. This is different from languages like C where unsigned integer underflow wraps around to the maximum value - that is x'FFFFFFFF'
This strict behavior in COBOL is part of its design philosophy for business applications, where unexpected numerical behaviors could lead to serious financial errors. COBOL prioritizes detecting these conditions rather than allowing silent wraparound.
Last edit: Ralph Linkletter 2025-02-07
Correction: The COBOL standard defines that checking for size errors is only enabled if either the
SIZE ERROR
phrase is used or (since COBOL2002) an applicable>> TURN
directive to enable that is used. Otherwise it is undefined.Before COBOL2002 the result of a
SIZE ERROR
without that phrase was undefined altogether.Using
ON SIZE ERROR
leads to the target field being unchanged.As all of the
EC-SIZE
are fatal, checking for them (if noON SIZE ERROR
is specified) without handling the exception would abend the runtime.I remember from a migration from ACUCOBOL-GT to OpenCOBOL that ACUCOBOL used the absolute value for unsigned result fields and truncated [following the rules for
MOVE
of an intermediate result to the final result] , while OpenCOBOL used to store zero or kept it unchanged. UsingON SIZE ERROR MOVE 0 TO result
created the same behavior for both environments.Note:
COMP-4
+COMP-5
(or the standard binary types) are an extension, so they can have implicit rules (and I'd expect a binary truncation/overflow in most cases).Ralph.
I had done a size error check before submitting the starting post to this thread.
It changes the result of the SUBTRACT verb.
Here is a screen shot.
Notice that it goes from 1 to 0 to 1 to 0 repeatedly/infinity.
Michael :-)
Last edit: Michael F Gleason 2025-02-08
Chuck and I have been analyzing the behavior of "0 - 1" across Micro Focus, Fujitsu, and GnuCOBOL.
3 different compilers - 3 different sets of results.
There is a very simple test case attached.
Try it - it highlight the behavior you are seeing but with displays of the binary data.
Good find
The issue originally discussed relating to COMPUTE vs SUBTRACT might not be an issue after all. When doing a subtract, the use of a GIVING or not changes how SUBTRACT works. The programmers guide (P.G.) documents three different SUBTRACT verbs. Reading VERY INTENTLY one sees that the three variations of SUBTRACT are different in functionality. SUBTRACT A FROM B will give you a different answer than SUBTRACT A FROM B GIVING C or SUBTRACT A FROM B GIVING B with the result being negative.
THAT IS WHEN WORKING WITH BINARY UNSIGNED DATA ITEMS FOR RESULTS.
Without the GIVING option, the function takes place in B. With the GIVING option, neither A nor B are modified, and the result is placed in C. (unless the giving is B.)
My conclusion is (SUBTRACT A FROM B GIVING B) is functionally the same as
(COMPUTE B = B - A) and one should take precautions if storing negative numbers in unsigned data items is likely. That is akin to not allowing dividing by zero.
Attached is a test case showing that GIVING is the way to go. I have tried several data definitions for the results. See the commented-out lines in the code if you are interested.
Michael :-)
Last edit: Michael F Gleason 2025-05-07