• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Guru: A Bevy of BIFs – %Dec to the Rescue

    August 1, 2018 Susan Gantner

    Author’s Note: This tip was first published back in 2009. I’ve updated the code examples here to use free format declarations. In addition I’ve added the potential use of %ScanRpl, which didn’t exist at the original publication date.

    More and more in RPG applications these days, it seems we need to process data that comes from “the dark side.” Translation: from a non-i system. This data could be coming from a browser screen via an RPG CGI program, from a CSV (comma-separated values) flat file, from an XML or JSON document, or myriad other ways. One thing these dark sources often have in common is that data that should be numeric often isn’t — at least not by RPG’s definition. So common is the issue of invalid numeric data that one of the recommendations from IBM on using the XML-INTO operation code is to define the fields in the DS to receive the XML data as character and then translate them into numeric fields using RPG logic later.

    I’ve seen several examples of some fairly complex logic to accomplish this translation from character to numeric, but many times the use of %Dec does the job much more simply. With a little help from %XLate and Monitor, %Dec can handle most of the situations that the more complex logic would have done.

    First, let’s look at the basics of the %Dec built-in function. The syntax for converting from character fields looks like the following.

      %DEC(character expression : length : decimal places)
    

    Notice that when converting from character data to numeric, the length/precision and decimal places are not optional.

    The %Dec built-in can also be used to control the precision of numeric expressions and also to convert date/time/timestamp data. The latter is very useful for moving database data back into numeric form after it had been translated to date/time/timestamp form for use with RPG’s native date-handling facilities. But our main focus here will be for converting data that should be numeric — but isn’t quite — so that we can use and/or store it appropriately in RPG.

    Of course, when the character data is clean — by RPG standards — the process is very simple, as illustrated in this example:

       Dcl-S CharField1 Char(14) Inz('     1525.95-');    
       NumField = %Dec(CharField1 : 9 : 2);
    

    RPG will accept and properly translate positive (+) or negative (-) signs either at the beginning or end of the numeric data. A decimal point can be specified and blanks are allowed anywhere in the expression/field. However, it won’t accept currency symbols, thousands separators, and asterisks.

    So how can we easily deal with those characters that could very feasibly occur in “numeric” fields? An easy way is to translate them into something that is allowed, such as spaces, using %XLate. Note that one of the powers of using functions is that often one can be used as a parameter value to another, so we’re not forced to do the old RPG/400 technique requiring temporary variables. If you’re not familiar with the details of %XLate, check out this tip from Jon Paris: A Bevy of BIFs: %XLATE and %REPLACE. An example of using it with %Dec is shown below. This code will replace all occurrences of either dollar sign, comma or asterisk with blanks before doing the numeric conversion.

       Dcl-S CharField2 Char(14) Inz('   $1,525.95-');
       NumField = %Dec( %XLate('$,*' : '   ' : CharField2 ) : 9 : 2);
    

    So far, so good. But what if something else appears in the supposedly numeric value that we haven’t anticipated? After all, it happens. Some weird unexplainable character appears in the field or some unsupported way of designating a negative value (such as parentheses) is used. In that case, %Dec will throw a status code 105 and error message RNX0105 (A character representation of a numeric value is in error.)

    That’s where our friend Monitor comes in. If you monitor for the error on the %Dec operation, you can then take appropriate action; whatever that action is for the situation where you’ve received bad data. The resulting code would then look something like the following:

      Dcl-S CharField3 Char(14) Inz('  $1,5Q25.95-');
         Monitor;
            NumField = %Dec(  %XLate('$,*' : '   ' : CharField3 ) : 9 : 2);
         On-Error 105;
              // Error handling logic goes here
         EndMon;
    

    Your error handling logic might simply log the transaction as an error for follow up later and move on to the next logical piece of data. In some cases, you may want to attempt to translate some other characters, for example a CR for negative numbers. For that situation, you’ll find the %ScanRpl (scan and replace characters) useful. An example of using it is in the example below. Why not use %ScanRpl instead of %XLate? It would have required a line of code for each character to be replaced whereas %XLate is very efficient at replacing multiple individual characters. I only need %ScanRpl when I need to replace a string of characters. You can learn more about %ScanRpl in the Guru tip: A Bevy of BIFs: %ScanRpl (Scan and Replace).

    Of course, hopefully we have all learned by now that hard-coding constant values in our logic is not productive during maintenance, so a better way of coding the logic might look like this:

       Dcl-S CharField4 Char(14) Inz('  $1,234.56 CR');
       Dcl-C NumberEdits  '$,*';
       Dcl-C Blanks4XLate '   ';
       Dcl-C BadNumData   105;   
       Monitor;
          NumField = %Dec( %XLate(NumberEdits : Blanks4XLate :
                      CharField4 ) : 9 : 2);
       On-Error BadNumData;
          Charfield4 = %ScanRpl('CR' : '-':
            %XLate(NumberEdits : Blanks4XLate : Charfield4));   
          // Any additional error handling logic may go here
       EndMon;
    

    In the example above, it may make more sense to create a temporary field to hold the results of the first %XLate so that that logic wouldn’t need to be repeated in the On-Error code.

    By the way, the technique of using Monitor to find the “problem fields” for you is typically more efficient than coding extensive bad data detection and handling logic yourself before using %Dec. This is because it’s highly likely that the vast majority of those so-called numeric values really are numeric, especially after taking care of some common issues, such as thousands separators and currency symbols. So there’s no need to run the bad data detection logic for all those fields that are good.

    As a matter of fact, if you think most of the data won’t even contain the currency symbol, thousands separator, etc., you could make it even more efficient by moving the %XLate function to the error handling routine instead of imbedding it into the %Dec function. Nested Monitor blocks work well for this. It would look something like this during maintenance, so a better way of coding the logic above might look like this:

      Monitor;                                                                                                            
         NumField = %Dec( CharField3 : 9 : 2 );                                                                                 
      On-Error BadNumData;                                                                                                     
         Monitor;                                                   
            NumField = %Dec( %XLate(NumberEdits : Blanks4XLate :     
                        CharField4 ) : 9 : 2);                     
         On-Error BadNumData;                                       
            // More error handling logic goes here                         
         EndMon;                                                                                                                                                                                                                    
      EndMon;                                                      
    

    So now you have a simple way to get those so-called numeric values into your numeric fields in your RPG programs, courtesy of a few RPG built-in functions.

    Susan Gantner, an IBM Champion and co-author of the popular Redbook Who Knew You Could Do That with RPG IV, is one of the top speakers/writers/trainers on IBM i development topics. She is a partner at Partner400 and System i Developer, and she hosts the RPG & DB2 Summit twice per year with partners Jon Paris and Paul Tuohy.

    RELATED STORIES

    A Bevy of BIFs: %ScanRpl (Scan and Replace)

    A Bevy of BIFs: %XLATE and %REPLACE

    A Bevy of BIFS: %SCAN And %Check

    Share this:

    • Share on Reddit (Opens in new window) Reddit
    • Share on Facebook (Opens in new window) Facebook
    • Share on LinkedIn (Opens in new window) LinkedIn
    • Share on X (Opens in new window) X
    • Email a link to a friend (Opens in new window) Email

    Tags: Tags: 400guruclassic, BIF, CSV, FHGC, Four Hundred Guru Classic, IBM i, JSON, RPG, RPG CGI, XML

    Sponsored by
    JAMS Software

    One Scheduler. IBM i, Windows, Linux, and More.

    IBM i teams trust JAMS to schedule and orchestrate jobs across every platform in their environment. Centralized visibility, cross-platform dependency management, and alerts that reach the right person before the business feels it.

    Fewer than 5% of IBM i shops run IBM i only. The rest are managing cross-platform dependencies — often without a clear picture of how they connect. JAMS draws that map, enforces those dependencies automatically, and gives your team a single place to monitor, manage, and recover when something goes wrong.

    If you are running hundreds of CL scripts and custom RPG processes, bring them as-is. JAMS runs them exactly as they do today — except now they are visible, monitored, and part of an orchestrated workflow instead of scattered across folders only one person knows about.

    No consumption-based pricing. No surprise bills when your workload spikes. You pay based on how many machines JAMS talks to — that’s it.

    Learn More → https://jamsscheduler.com/lp/ibm-i

    Share this:

    • Share on Reddit (Opens in new window) Reddit
    • Share on Facebook (Opens in new window) Facebook
    • Share on LinkedIn (Opens in new window) LinkedIn
    • Share on X (Opens in new window) X
    • Email a link to a friend (Opens in new window) Email

    Guru: An Introduction to RPG’s XML-INTO, Part 1 IBM i PTF Guide, Volume 20, Number 30

    Leave a ReplyCancel reply

TFH Volume: 28 Issue: 51

This Issue Sponsored By

  • RPG & DB2 Summit
  • RPG & DB2 Summit
  • RPG & DB2 Summit

Table of Contents

  • Guru: A Bevy of BIFs – %Dec to the Rescue
  • Guru: An Introduction to RPG’s XML-INTO, Part 1
  • Guru: Getting The Message, Part 1

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • Inside The Encryption Key Management Changes In IBM i 7.6
  • FalconStor Moved To The Blue Lagoon, And Is Poised For Growth Because Of It
  • Guru: Claude’s SQL Tip
  • Astera Makes Extracting Legacy Report Data an AI Specialty
  • IBM i PTF Guide, Volume 28, Number 27
  • Welcoming The New IBM i Chief Architect And Other New Top Brass
  • A Deep Dive Into That Power S1112 Entry Power11 Server
  • Guru: Beyond Three-Part Naming – Running SQL Across Remote IBM i Systems
  • How IBM Bolstered IBM i Resilience In The Summer Tech Refreshes
  • IBM i PTF Guide, Volume 28, Number 26

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle