ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Implicit casting oddities

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Implicit casting oddities

    Hello everybody. Faced with colleagues with the following problem. Here is some C code to illustrate it:
    Code:
    #include <stdio.h>
    #include <decimal.h>
    #include <string.h>
    #include <xxcvt.h>
    
    int main()
    {
      unsigned char zoned[7];
      memcpy(zoned, "0006200", 7);
    
      double d = QXXZTOD(zoned, 7, 4); 
      printf("zoned to double = %f\n", d);  
    
      decimal(7,4) dec = d; 
      printf("double to decimal = %D(7,4)\n", dec);
    }

    In this code, printing the d variable displays 0.620000. However, after storing this variable in a decimal variable (7,4) and printing it to the screen, the number 0.6199 is displayed. If this code is compiled with a C ++ compiler, then the problem is not reproduced. Can you explain why the precision is lost when saving to decimal?

  • #2
    When you print with printf, it's probably rounding it. I would avoid the use of float/double unless you absolutely must have them for some reason. They cause all sorts of problems like this! Instead, convert the zoned field directly to decimal, and use that.

    Comment


    • #3
      Originally posted by Scott Klement View Post
      Instead, convert the zoned field directly to decimal, and use that.
      Scott, I wouldn't mind a direct conversion from zoned to decimal. But how to do that? I don't know of a standard function from the C / 400 library that does this.

      Comment


      • d7d1cd_
        d7d1cd_ commented
        Editing a comment
        P.S. Again, everything works correctly in C++!

    • #4
      If, by the way, in the specified code you use not an explicit assignment (dec = d), but do it through the QXXDTOP function, then there is no loss of precision.
      But as a result, 2 functions are needed to convert zoned to packed decimal. Somehow difficult for such a simple operation ...

      Comment


      • #5
        Sorry for the slow response, I've been very busy with end-of-year stuff. If you don't have a better way, it seems like you could use the _LBCPYNV MI builtin to convert this:


        There should be a prototype, et al, in the include file, QSYSINC/MIH,LBCPYNV

        As for why it doesn't work the same in C vs C++... you'd have to ask IBM.

        Comment


        • #6
          Scott, thanks a lot for the tip! Created a function for converting, everything works fine!
          Code:
          void ZonToDec(void* zon, void* dec, int dig, int fra)
          {
            _DPA_Template_T zonAttr = { _T_ZONED, (fra << 8) + dig };
            _DPA_Template_T decAttr = zonAttr;
            decAttr.Type = _T_PACKED;
          
            _LBCPYNV(dec, &decAttr, zon, &zonAttr); 
          }

          Comment

          Working...
          X