COBOL

COBOL

COBOL

COBOL is responsible for the efficient, reliable, secure, and unseen day-to-day operations of the world's economy.

 View Only
  • 1.  Realistic usage of NUMVAL functions

    Posted Mon April 08, 2019 05:56 PM

    Even though the NUMVAL and NUMVAL-C functions have been available for over 20 years, I've never "seriously" used it because of the fact that it (intentionally) causes an abend when given non-conforming input.

     

    Now that the new TEST-NUMVAL functions have been added I thought I'd try it out.  Seems to work fine.  My issue now is that I can't figure out how to determine if input is valid, but does not conform to the picture clause of the field its being assigned to.  Take the following example:

     01  input-area          pic x(16).
     01  num-val             pic s9(4) comp.


         accept input-area
         if function numval(input-area) = 0
             compute num-val = function numval(input-area)
         else
             display 'invalid numeric input: '
             stop run
         end-if

         display 'you entered: ' num-val

    If the input string is, for example, 1234.56 then num-val is rounded up to 1235.  I can't figure out a way, other than a manual scan of the string, to determine if the input is this type of invalid (too many digits to the right of the decimal point).

    Any ideas?

     

    fswarbrick


  • 2.  Re: Realistic usage of NUMVAL functions

    Posted Wed April 17, 2019 02:56 PM

    Hi Frank,

    Thanks for your input on the TEST-NUMVAL function and the COBOL team has reviewed it.

    As a solution to your specific problem, we have the following solution using the INTEGER-PART intrinsic function to determine if NUMVAL returns an integer which conforms to your pic s9(4) comp data item:

              01  input-area          pic x(16).
              01  num-val             pic s9(4) comp.
              01  int-val             pic 9(5)v9(4).

                  accept input-area
                  if function test-numval(input-area) = 0
                      compute num-val = function numval(input-area)
                  else
                      display 'invalid numeric input: '
                      stop run
                  end-if
                  
                  compute int-val =
                  FUNCTION INTEGER-PART(FUNCTION NUMVAL(input-area)).
                  
                  IF int-val = FUNCTION NUMVAL(INPUT-AREA) THEN
                  display 'Input conforms to output'
                  display 'you entered: ' num-val               
                  else
                  display 'Input DOES NOT conform to output'.

     

    More generally, you're right. Other than a manual scan of the string, there really is no easy way of doing it.

    This would be a nice feature to have in the Enterprise COBOL Compiler. If you would like to see a solution as a function where the function determines if the input conforms to a particular picture clause, please open an RFE and we will look into it.

    aaksoy


  • 3.  Re: Realistic usage of NUMVAL functions

    Posted Wed June 05, 2019 08:31 PM

    So, whilst pursuing the COBOL 2014 ISO standard (as one does) I had a thought.  The standard allows for one of a number of "rounding modes" to be specified.  One of these is the mode called "PROHIBITED".  This means that if "the arithmetic value cannot be represented exactly in the resultant identifier, the EC-SIZE-TRUNCATION exception condition is set to exist, the size error condition exists, and the content of the resultant identifier is unchanged."

    For example, given num-val as above, if you specified the statement `COMPUTE num-val ROUNDED MODE IS PROHIBITED = 9.1`, I believe that this would trigger the EC-SIZE-TRUNCATION exception, and any ON SIZE ERROR clause, if present, would be invoked.  So in turn, if we had the statement `COMPUTE num-val ROUNDED MODE IS PROHIBITED = FUNCTION NUMVAL(input-area)`, if (in this case) there was any non-zero digit following the decimal point, it should also trigger the same exception.

    This seems to me a fairly elegant solution to the issue.  And of course adding ROUNDED MODE to Enterprise COBOL could be useful beyond this particular use case.

    I do have a concern, however.  It appears that currently even if no ROUNDED phrase is specified, if the "sending item" is one of the NUMVAL functions the result is still being rounded (up).  I don't know if this has anything to do with the note in the Enterprise COBOL reference  for the ROUNDED phrase that states "In a floating-point arithmetic operation, the ROUNDED phrase has no effect; the result of a floating-point operation is always rounded", but it seems to me that this should not occur if the "receiving item" is not a floating point data item.

    Anyway, I would be glad to open an RFE to support the additional rounding modes if the IBM COBOL team thinks its something they might realistically implement.

    Thanks!  Frank

    fswarbrick


  • 4.  Re: Realistic usage of NUMVAL functions

    Posted Mon May 20, 2019 11:55 PM

    Thanks

    choibaisunwin


  • 5.  Re: Realistic usage of NUMVAL functions

    Posted Sat June 08, 2019 08:11 PM

    So the answer came to me in a dream (almost literally).  After converting the string to a number using the appropriate NUMVAL function, you can then immediately compare the result to the same NUMVAL function.  If they are equal, then there was no overflow or truncation.  Otherwise there was.  Easy peasey?

     identification division.                                     
     program-id. valnum.                                          
                                                                  
     data division.                                               
     working-storage section.                                     
     01  pic x value low-values.                                  
         88  never value high-values.                             
     01  input-string                pic x(12).                   
     01  input-amount                pic 9(5)v99 comp-3.          
     01  output-amount               pic z(4)9.99.                
     01  r                           pic 9(4) comp.               
     01  r-out                       pic z(3)9.                   
                                                                  
     procedure division.                                          
         perform with test after until never                      
             move low-values to input-string                      
             accept input-string                                  
             if input-string = low-values                         
                 exit perform                                     
             end-if                                               
             compute r = function test-numval(input-string)       
             if r = 0                                             
                 compute input-amount =                           
                         function numval(input-string)            
                 if input-amount = function numval(input-string)  
                     move input-amount to output-amount           
                     display function trim(input-string)          
                             space '=' space                      
                             function trim(output-amount leading)
                             space                                
                             '(' input-amount ')'                 
                 else                                             
                     display 'Invalid input: ' input-string       
                 end-if                                      
             else                                            
                 move r to r-out                             
                 display 'Invalid numeric input at position '
                         function trim(r-out leading)        
                         ': ' input-string                   
             end-if                                          
         end-perform                                         
         stop run.                                           

    No new language features required!

    Here's some input:

    123      
    123.9    
    123.99   
    123.990  
    123.001  
    123.991  
    123.999  
    99999    
    99999.9  
    99999.99
    99999.999
    100000   
    ABC123   
    123ABC  

    And the output:

    123 = 123.00 (0012300)                      
    123.9 = 123.90 (0012390)                    
    123.99 = 123.99 (0012399)                   
    123.990 = 123.99 (0012399)                  
    Invalid input: 123.001                      
    Invalid input: 123.991                      
    Invalid input: 123.999                      
    99999 = 99999.00 (9999900)                  
    99999.9 = 99999.90 (9999990)                
    99999.99 = 99999.99 (9999999)               
    Invalid input: 99999.999                    
    Invalid input: 100000                       
    Invalid numeric input at position 13: ABC123
    Invalid numeric input at position 5: 123ABC

    Am I missing anything?

    fswarbrick