Apologize in advance, cause this is goofy; but I am stumped by something I encountered doing a COBOL exercise. It involves data storage in GnuCOBOL.
Essentially I derived a string of zeros and ones (12 digits worth) and needed to express them in an integer.
Externally to the program, using an online binary to decimal converter, I determined that the long string
000000100100 was the equivalent of 36 in decimal. That said I have no idea how to have the program
take in a 12 digit 9(12) string of 000000100100 and have it produce the 36 I ultimately desire.
I tried moving the 12 digits into a Comp field.. and the results were not what I wanted.
Does anyone know how to do this?
Thank you in advance.
Steve
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
So when you have a string that contains a binary representation and you want to convert it to an integer the most reasonable (and portable) approach to me seems to get to the end of the string and then inspect each position going backwards, adding to a target in a loop ADD 2 ** POSITION TO TARGET.
To MOVE from/to binary representation you could have a look at the BIT-OF and BIT-TO-CHAR functions (non-portable, originated from IBM only available in very current versions of GnuCOBOL).
Last edit: Simon Sobisch 2021-12-04
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Got it now. Was looking for a simple move; but that was not going to happen.
Ended up mapping and interpreting the binary nibbles as 4 digit values so that 0001=1, 0010=2, etc. and by this means building a hexidecimal number.. and then interpreting the hex values back into decimal (by multiplying the rightmost position in the hex number by 1, the next column by 16, the third by 256 (16 squared), the next column by 1024 (256 * 16) and so on.. Once I had the decimal value, I could use it as I wanted in the program.
On mainframe have dealt with Comp-3 a lot, Comp a little; but on the Windows platform GnuCOBOL has a lot of binary representations that are very foreign to me. I'll tackle them if I need to; but for now I am good.
Thanks @sf-mensch for taking the time to respond. It helped me to figure out what I needed to do.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Steve, I spent many years converting COMP-3 to other data types. I enclose a GC version that features one of the most common routines we used way back then. This particular code converts any size COMP-3 field to a string that is terminated with a sign character ('-' or '+'). This may not look efficient but it runs very quickly which was a priority when converting millions of records.
Gregory, thanks for posting this.
Could you please recheck for the copyright and add a notice in the program header?
To be more portable you may want to drop the FUNCTION ALL INTRINSIC (which is unused in this program) and apply the following change:
MOVE ZEROES TO SIZEOF-TEST-COMP3.
- INSPECT TEST-COMP3+ INSPECT TEST-COMP3 (1:)
TALLYING SIZEOF-TEST-COMP3 FOR CHARACTERS.
or get rid of that complete code part and replace it with
MOVELENGTHOFTEST-COMP3TOSIZEOF-TEST-COMP3.
If you have access to a current GC version you can get rid of the extra computation and temporary values completely, which should get you a much faster version as follows:
Some very cool suggestions you have made. I am sure the code can be improved by using your suggestions but I need to explain that the section that does all the work is lifted from a 30 year old program! It had to make use of whatever the RM-Cobol compiler (rel 6 or so) allowed. 'length of' and 'b-and' were not in the toolbox. In fact 'logical' functions were not available in any form so we had to write and link in small 'c' modules to provide that functionality via a 'CALL'. The 'CALL 'CBL_AND' USING X1, X0X, BY VALUE 1' replaces the old code. A few other changes are in there to get through the GC compiler. I agree the REPOSITORY lines are not needed (copy-paste from another GC program used).
I do have a question ... how does this change improve things?
The 'INSPECT' obviously considers 'TEST-COMP3' to be DISPLAY data with a length of 6 bytes, so how does the sub-scripting help?
BTW I am using :
cobc (GnuCOBOL) 3.1-dev.0
Built Jul 09 2019 09:01:09 Packaged Jul 09 2019 13:58:39 UTC
C version "4.8.3 20140627 [gcc-4_8-branch revision 212064]"
Anyway thanks for the suggestions. Good to hear from you. Stay safe.
Gregory
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The 'INSPECT' obviously considers 'TEST-COMP3' to be DISPLAY data with a length of 6 bytes, so how does the sub-scripting help?
Actually you are not allowed to use a COMP-3 item there according to the standard:
Identifier-1 shall reference either an alphanumeric or national group item or an elementary item described implicitly or explicitly as usage display or national.
And the "trick" here is that a ref-mod of (1:) creates an implicit USAGE DISPLAY item (if the data-name that belongs to the ref-mod isn't USAGE NATIONAL.
But as noted: the complete part can be dropped with the LENGTH OF special register (which I think is also available in old RM-COBOL).
If the code itself is CALLed you'd use that, otherwise PERFORM LENGTH OF TIMES directly is again faster.
b-and is very new to GnuCOBOL. As you use a dev-version of 3.1 I'd highly suggest to update to 3.2-dev instead (backward compatible so you likely don't need to recompile anything you don't want to).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I compiled this program with RMCobol v12 and it did indeed complain about the 'TEST-COMP3' field in the 'INSPECT' statement. I tracked down the original program and saw that the 'TEST-COMP3' fields had definitions that looked like this:
Then in the code the INSPECT referenced 'INN-RECD-FIELD-032X' which allowed it to work properly. So your suggestion to use a ref-mod to create an implicit DISPLAY is a cool workaround.
I also went back to the RMCobol manuals for V6 and V12. There are no methods to simulate a 'length of' phrase other than the INSPECT TALLYING statement. An exception to this is there are a few extensions that allow the code to acquire the field statistics of fields stated in the USING part of a CALL.
Interestingly there are logical functions available in RMCobol v12 ie 'C$LogicalAnd', 'C$LogicalOr', etc. Maybe RMC will catch up with GC someday.
Gregory
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hm, RM/COBOL Language Reference Manual for version 9 / 12 says it supports LENGTH OF identifier and supports also ref-mod with variable length or OCCURS DEPENDING ON variable length - so actually works as FUNCTION LENGTH (identifier) does (at least some dialects don't allow those with the special register LENGTH OF.
Did we look at different docs? It is possible (but still not that likely) that the LENGTH OF special register did not exist in version 6.
The "Subprogram Library" in the RM/COBOL User's Guide is interesting. We do have a bunch of those (mostly from the docs of ACUCOBOL-GT), but not all. Many are similar but not identical to existing ones so I guess I'll have a look at those next year.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OK ... according to my printed documentation, in RMCobol v6 there was no special register that supported 'length of' but by v12 is was there. I don't know when that came to be (RMC v9 or so) but the lack of 'length of' in RMC v6 explains why INSPECT/TALLYING was used back in the 80s.
The RMC 'C$LogicalAnd' subprogram works but is very picky about the format. This format compiles cleanly but fails at runtime:
01 XOX PIC 9(01) BINARY(1).
...
MOVE 240 TO XOX
CALL "C$LogicalAnd" USING XOX, X1
While thinking about our discussion it occurred to me that since GC did not throw a warning or error message when it encountered 'INSPECT TEXT-COMP3' someone should put that small tidbit on the repair queue. Since it produces correct results probably a warning should be sufficient.
Just sayin' ...
Gregory
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Apologize in advance, cause this is goofy; but I am stumped by something I encountered doing a COBOL exercise. It involves data storage in GnuCOBOL.
Essentially I derived a string of zeros and ones (12 digits worth) and needed to express them in an integer.
Externally to the program, using an online binary to decimal converter, I determined that the long string
000000100100 was the equivalent of 36 in decimal. That said I have no idea how to have the program
take in a 12 digit 9(12) string of 000000100100 and have it produce the 36 I ultimately desire.
I tried moving the 12 digits into a Comp field.. and the results were not what I wanted.
Does anyone know how to do this?
Thank you in advance.
Steve
So when you have a string that contains a binary representation and you want to convert it to an integer the most reasonable (and portable) approach to me seems to get to the end of the string and then inspect each position going backwards, adding to a target in a loop
ADD 2 ** POSITION TO TARGET
.To
MOVE
from/to binary representation you could have a look at theBIT-OF
andBIT-TO-CHAR
functions (non-portable, originated from IBM only available in very current versions of GnuCOBOL).Last edit: Simon Sobisch 2021-12-04
Got it now. Was looking for a simple move; but that was not going to happen.
Ended up mapping and interpreting the binary nibbles as 4 digit values so that 0001=1, 0010=2, etc. and by this means building a hexidecimal number.. and then interpreting the hex values back into decimal (by multiplying the rightmost position in the hex number by 1, the next column by 16, the third by 256 (16 squared), the next column by 1024 (256 * 16) and so on.. Once I had the decimal value, I could use it as I wanted in the program.
On mainframe have dealt with Comp-3 a lot, Comp a little; but on the Windows platform GnuCOBOL has a lot of binary representations that are very foreign to me. I'll tackle them if I need to; but for now I am good.
Thanks @sf-mensch for taking the time to respond. It helped me to figure out what I needed to do.
Steve, I spent many years converting COMP-3 to other data types. I enclose a GC version that features one of the most common routines we used way back then. This particular code converts any size COMP-3 field to a string that is terminated with a sign character ('-' or '+'). This may not look efficient but it runs very quickly which was a priority when converting millions of records.
Regards
Gregory, thanks for posting this.
Could you please recheck for the copyright and add a notice in the program header?
To be more portable you may want to drop the
FUNCTION ALL INTRINSIC
(which is unused in this program) and apply the following change:or get rid of that complete code part and replace it with
If you have access to a current GC version you can get rid of the extra computation and temporary values completely, which should get you a much faster version as follows:
Simon,
Some very cool suggestions you have made. I am sure the code can be improved by using your suggestions but I need to explain that the section that does all the work is lifted from a 30 year old program! It had to make use of whatever the RM-Cobol compiler (rel 6 or so) allowed. 'length of' and 'b-and' were not in the toolbox. In fact 'logical' functions were not available in any form so we had to write and link in small 'c' modules to provide that functionality via a 'CALL'. The 'CALL 'CBL_AND' USING X1, X0X, BY VALUE 1' replaces the old code. A few other changes are in there to get through the GC compiler. I agree the REPOSITORY lines are not needed (copy-paste from another GC program used).
I do have a question ... how does this change improve things?
The 'INSPECT' obviously considers 'TEST-COMP3' to be DISPLAY data with a length of 6 bytes, so how does the sub-scripting help?
BTW I am using :
cobc (GnuCOBOL) 3.1-dev.0
Built Jul 09 2019 09:01:09 Packaged Jul 09 2019 13:58:39 UTC
C version "4.8.3 20140627 [gcc-4_8-branch revision 212064]"
Anyway thanks for the suggestions. Good to hear from you. Stay safe.
Gregory
Actually you are not allowed to use a
COMP-3
item there according to the standard:And the "trick" here is that a ref-mod of
(1:)
creates an implicitUSAGE DISPLAY
item (if the data-name that belongs to the ref-mod isn'tUSAGE NATIONAL
.But as noted: the complete part can be dropped with the
LENGTH OF
special register (which I think is also available in old RM-COBOL).If the code itself is
CALL
ed you'd use that, otherwisePERFORM LENGTH OF TIMES
directly is again faster.b-and
is very new to GnuCOBOL. As you use a dev-version of 3.1 I'd highly suggest to update to 3.2-dev instead (backward compatible so you likely don't need to recompile anything you don't want to).Hey Simon,
I compiled this program with RMCobol v12 and it did indeed complain about the 'TEST-COMP3' field in the 'INSPECT' statement. I tracked down the original program and saw that the 'TEST-COMP3' fields had definitions that looked like this:
Then in the code the INSPECT referenced 'INN-RECD-FIELD-032X' which allowed it to work properly. So your suggestion to use a ref-mod to create an implicit DISPLAY is a cool workaround.
I also went back to the RMCobol manuals for V6 and V12. There are no methods to simulate a 'length of' phrase other than the INSPECT TALLYING statement. An exception to this is there are a few extensions that allow the code to acquire the field statistics of fields stated in the USING part of a CALL.
Interestingly there are logical functions available in RMCobol v12 ie 'C$LogicalAnd', 'C$LogicalOr', etc. Maybe RMC will catch up with GC someday.
Gregory
Hm, RM/COBOL Language Reference Manual for version 9 / 12 says it supports
LENGTH OF identifier
and supports also ref-mod with variable length orOCCURS DEPENDING ON
variable length - so actually works asFUNCTION LENGTH (identifier)
does (at least some dialects don't allow those with the special registerLENGTH OF
.Did we look at different docs? It is possible (but still not that likely) that the
LENGTH OF
special register did not exist in version 6.The "Subprogram Library" in the RM/COBOL User's Guide is interesting. We do have a bunch of those (mostly from the docs of ACUCOBOL-GT), but not all. Many are similar but not identical to existing ones so I guess I'll have a look at those next year.
OK ... according to my printed documentation, in RMCobol v6 there was no special register that supported 'length of' but by v12 is was there. I don't know when that came to be (RMC v9 or so) but the lack of 'length of' in RMC v6 explains why INSPECT/TALLYING was used back in the 80s.
The RMC 'C$LogicalAnd' subprogram works but is very picky about the format. This format compiles cleanly but fails at runtime:
... while this format works:
Anyway, I think we have beaten this horse enough - stay safe and healthy.
Gregory
Simon,
While thinking about our discussion it occurred to me that since GC did not throw a warning or error message when it encountered 'INSPECT TEXT-COMP3' someone should put that small tidbit on the repair queue. Since it produces correct results probably a warning should be sufficient.
Just sayin' ...
Gregory