Menu

Moving data to and from Binary

Anonymous
2021-12-04
2021-12-30
  • Anonymous

    Anonymous - 2021-12-04

    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

     
  • Simon Sobisch

    Simon Sobisch - 2021-12-04

    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
  • Steve Millman

    Steve Millman - 2021-12-10

    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.

     
    • Gregory A Failing

      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

       
      • Simon Sobisch

        Simon Sobisch - 2021-12-29

        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

                     MOVE LENGTH OF TEST-COMP3
                       TO SIZEOF-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:

               01  X1.
                  03  X0X                BINARY-CHAR UNSIGNED.
        
        ...
        
                   MOVE 1 TO NDXB, NDXA.
                   PERFORM SIZEOF-TEST-COMP3 TIMES
              * process high-order nybble ...
                       MOVE TEST-COMP3(NDXA:1) TO X1
                       EVALUATE (X0X b-and 240) / 16
                           WHEN 0      MOVE '0' TO DEST-STRING(NDXB:1)
                           WHEN 1      MOVE '1' TO DEST-STRING(NDXB:1)
                           WHEN 2      MOVE '2' TO DEST-STRING(NDXB:1)
                           WHEN 3      MOVE '3' TO DEST-STRING(NDXB:1)
                           WHEN 4      MOVE '4' TO DEST-STRING(NDXB:1)
                           WHEN 5      MOVE '5' TO DEST-STRING(NDXB:1)
                           WHEN 6      MOVE '6' TO DEST-STRING(NDXB:1)
                           WHEN 7      MOVE '7' TO DEST-STRING(NDXB:1)
                           WHEN 8      MOVE '8' TO DEST-STRING(NDXB:1)
                           WHEN 9      MOVE '9' TO DEST-STRING(NDXB:1)
                           WHEN OTHER  MOVE '+' TO DEST-STRING(NDXB:1)
                       END-EVALUATE
                       ADD 1 TO NDXB
              * process low-order nybble ...
                       MOVE TEST-COMP3(NDXA:1) TO X1
                       EVALUATE X0X b-and 15
                           WHEN 0      MOVE '0' TO DEST-STRING(NDXB:1)
                           WHEN 1      MOVE '1' TO DEST-STRING(NDXB:1)
                           WHEN 2      MOVE '2' TO DEST-STRING(NDXB:1)
                           WHEN 3      MOVE '3' TO DEST-STRING(NDXB:1)
                           WHEN 4      MOVE '4' TO DEST-STRING(NDXB:1)
                           WHEN 5      MOVE '5' TO DEST-STRING(NDXB:1)
                           WHEN 6      MOVE '6' TO DEST-STRING(NDXB:1)
                           WHEN 7      MOVE '7' TO DEST-STRING(NDXB:1)
                           WHEN 8      MOVE '8' TO DEST-STRING(NDXB:1)
                           WHEN 9      MOVE '9' TO DEST-STRING(NDXB:1)
                           WHEN 13     MOVE '-' TO DEST-STRING(NDXB:1)
                           WHEN OTHER  MOVE '+' TO DEST-STRING(NDXB:1)
                       END-EVALUATE
                       ADD 1 TO NDXB, NDXA
                   END-PERFORM.
        
         
        • Gregory A Failing

          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?

                      MOVE ZEROES TO SIZEOF-TEST-COMP3.
          -           INSPECT TEST-COMP3
          +           INSPECT TEST-COMP3 (1:)
                          TALLYING SIZEOF-TEST-COMP3 FOR CHARACTERS.
          

          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

           
  • Simon Sobisch

    Simon Sobisch - 2021-12-29

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

     
    • Gregory A Failing

      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:

      ...
      01  INN-RECD.
      ...
          03 INN-RECD-FIELD-032X.
                    05 INN-RECD-FIELD-032  PIC S9(11)  COMP-3.
       ...
      

      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

       
      • Simon Sobisch

        Simon Sobisch - 2021-12-29

        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.

         
        • Gregory A Failing

          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 this format works:

                 01  XOX                    PIC 9(01)      BINARY(1).
          
                         CALL "C$LogicalAnd" GIVING XOX USING H'F0', X1
          

          Anyway, I think we have beaten this horse enough - stay safe and healthy.

          Gregory

           
  • Gregory A Failing

    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

     

Anonymous
Anonymous

Add attachments
Cancel