Skip to Content

Recently I stumbled over the examples in the documentation of built-in functions ROUND and RESCALE.

(Does anybody use RESCALE?)

There are tables with results of these functions for different values of the arguments, but there was no coding example how to achieve these results. I guess,  the functions were called  with different arguments one by one and the results were copied into the documentation one by one.

But, hey, we have other possibilities in ABAP now and I’ve tried to recreate the results with CL_DEMO_OUTPUT and REDUCE (as a recreational measure so to say).

I cannot refrain from showing you that (a bit of showing off):

TYPES:
   BEGIN OF line,
     arg       TYPE i,
     result    TYPE decfloat34,
     scale     TYPE i,
     precision TYPE i,
   END OF line,
   result TYPE STANDARD TABLE OF line WITH EMPTY KEY.

DATA(val) = CONV decfloat34( ‘1234.56789 ‘ ).
DATA(out) = cl_demo_output=>new(
   )->begin_section( ‘Value’
   )->write(
     |{ val
      }, scale = { cl_abap_math=>get_scale( val )
      }, precision = { cl_abap_math=>get_number_of_digits( val ) }|
   )->begin_section( ‘Round with dec’
   )->write(
    REDUCE result(
      INIT tab TYPE result
      FOR i = 5 UNTIL i > 6
      LET rddec = round( val = val dec = i
          mode  = cl_abap_math=>round_half_up ) IN
      NEXT tab = VALUE #( BASE tab
       ( arg = i
         result = rddec
         scale = cl_abap_math=>get_scale( rddec )
         precision = cl_abap_math=>get_number_of_digits( rddec )
       ) ) )
   )->next_section( ‘Round with prec’
   )->write(
    REDUCE result(
      INIT tab TYPE result
      FOR i = UNTIL i > 10
      LET rdprec = round( val = val prec = i
          mode   = cl_abap_math=>round_half_up ) IN
      NEXT tab = VALUE #( BASE tab
       ( arg = i
         result = rdprec
         scale = cl_abap_math=>get_scale( rdprec )
         precision = cl_abap_math=>get_number_of_digits( rdprec )
       ) ) )
   )->next_section( ‘Rescale with dec’
   )->write(
    REDUCE result(
      INIT tab TYPE result
      FOR i = 5 UNTIL i > 8
      LET rsdec = rescale( val = val dec = i
          mode  = cl_abap_math=>round_half_up ) IN
      NEXT tab  = VALUE #( BASE tab
       ( arg = i
         result = rsdec
         scale = cl_abap_math=>get_scale( rsdec )
         precision = cl_abap_math=>get_number_of_digits( rsdec )
       ) ) )
   )->next_section( ‘Rescale with prec’
   )->write(
    REDUCE result(
      INIT tab TYPE result
      FOR i = UNTIL i > 12
      LET rsprec = rescale( val = val prec = i
          mode   = cl_abap_math=>round_half_up ) IN
      NEXT tab = VALUE #( BASE tab
       ( arg = i
         result = rsprec
         scale = cl_abap_math=>get_scale( rsprec )
         precision = cl_abap_math=>get_number_of_digits( rsprec )
       ) ) )
   )->display( ).

Giving

/wp-content/uploads/2016/08/reduce_1023009.jpg

Isn’t REDUCE just awesome? For me, one of the most powerful of all the constructor operators. Use it to get used to it. Believe me, after some training, you even don’t have to look up its documentation any more.

To report this post you need to login first.

13 Comments

You must be Logged on to comment or reply to a post.

  1. Suhas Saha

    Isn’t REDUCE just awesome? For me, one of the most powerful of all the constructor operators. Use it to get used to it.

    I use the REDUCE (aka table-reduction) operator often in productive code. Imo, it makes the code so much cleaner 😘

    (1) 
  2. Jelena Perfiljeva

    Does anybody use RESCALE?

    Arrgh, stop rubbing it in, Horst! Our system is too old even for the “Next generation ABAP development”. 🙁

    I do appreciate your samples though, thank you!

    (0) 
      1. Sandra Rossi

        Thx. But I didn’t explain well my question. I couldn’t test it until today, but the first REDUCE is equivalent to this VALUE expression:

            VALUE result(
              FOR i = -5 UNTIL i > 6
              LET rddec = round( val = val dec = i
                  mode  = cl_abap_math=>round_half_up ) IN
              ( VALUE #(
                 arg = i
                 result = rddec
                 scale = cl_abap_math=>get_scale( rddec )
                 precision = cl_abap_math=>get_number_of_digits( rddec )
               ) ) )
        

        So, is there a reason to use REDUCE instead of VALUE? 😉

        (0) 
        1. Horst Keller Post author

          In fact no, you can replace all the REDUCEs with your VALUEs in this case 😡 .

          Let’s say it is a question of taste. When I have such a task, I start with REDUCE, because I LOVE it 😛

          PS: Sandra, your’e simply the best …

          (0) 
  3. Stefan Riedel-Seifert

    Very cool, but it seems, that i cannot solve the following problem with the statement reduce:

    assuming having an internal table with the follwing entries:

    KEY	BUSINESS_AREA	PROCESS_COMMUNICATION
    1	1		1
    1	1		2
    1	2		2
    1	3		1

    The content should be used in a table grid, but only one line per object

    KEY 	BUSINESS_AREA 	PROCESS_COMMUNICATION
    1 	1,2,3		1,2

    i.e. i have to reduce the content by the key like a projection. The separation of the content should be flexible: , or ‘<br/>’, …

    I played around with the reduce-statement, but could not solve this and ended up something like (control level processing):

    loop at it_data into data(wa_data).
      at new key.
        ...
      endat.
      at new business_area.
        ...
      endat.
      ...
    endloop.

     

    (0) 
    1. Horst Keller Post author

       

      TYPES:
        BEGIN OF line,
          key  TYPE i,
          col1 TYPE string,
          col2 TYPE string,
        END OF line,
        itab TYPE TABLE OF line WITH EMPTY KEY.
      
      DATA(itab) = VALUE itab(
        ( key = 1 col1 = `1` col2 = `1` )
        ( key = 1 col1 = `1` col2 = `2` )
        ( key = 1 col1 = `2` col2 = `2` )
        ( key = 1 col1 = `3` col2 = `1` ) ).
      
      DATA(result) = REDUCE line(
        INIT r TYPE line
        FOR GROUPS OF wa IN itab GROUP BY wa-key
        FOR mem IN GROUP wa
        NEXT r = VALUE #( LET buff = r IN
                          key = mem-key
                          col1 = buff-col1 && cond #( when buff-col1 ns mem-col1 then mem-col1 )
                          col2 = buff-col2 && cond #( when buff-col2 ns mem-col2 then mem-col2 ) ) ).
      ​
      (0) 
  4. Stefan Riedel-Seifert

    That’s a very good starting point. Assume having this internal table

    DATA(itab) = VALUE itab( ( key = 1 col1 = `1` col2 = `1` )
                             ( key = 1 col1 = `3` col2 = `2` )
                             ( key = 1 col1 = `2` col2 = `2` )
                             ( key = 1 col1 = `3` col2 = `1` )
                             ( key = 2 col1 = `4` col2 = `1` )
                             ( key = 2 col1 = `4` col2 = `2` )
                             ( key = 2 col1 = `5` col2 = `5` )
                             ( key = 2 col1 = `8` col2 = `1` ) ).

    and the goal is this output

    KEY COL1 COL2
    1 1,2,3 1,2
    2 4,5,8 1,2,5

     

    I slightly changed your code to

     

    SORT itab BY col1 col2.
    
    DATA(results) =
      REDUCE itab(
        INIT tab TYPE result
        FOR GROUPS OF wa IN itab GROUP BY wa-key
    
        NEXT tab = VALUE #(
        BASE tab
         (
          REDUCE line(
          INIT r TYPE line
          FOR mem IN GROUP wa
    
          NEXT r = VALUE #( LET buff = r IN
                            key  = mem-key
    
          col1 = COND #( WHEN buff-col1 IS INITIAL THEN buff-col1 && COND #( WHEN buff-col1 NS mem-col1 THEN        mem-col1 )
                         ELSE buff-col1                           && COND #( WHEN buff-col1 NS mem-col1 THEN ',' && mem-col1 ) )
    
          col2 = COND #( WHEN buff-col2 IS INITIAL THEN buff-col2 && COND #( WHEN buff-col2 NS mem-col2 THEN        mem-col2 )
                         ELSE buff-col2                           && COND #( WHEN buff-col2 NS mem-col2 THEN ',' && mem-col2 ) )
        ) )  ) ) ).
    
    cl_demo_output=>display( results ).
    

    to achieve this. Maybe, that this coding can be condensed :-).

    By the way: some trivial performance considerations:

    1) My first old fashioned try with at. … endat. constructions cost. approx 23.000 microseconds

    2) The new one more than twice (55.000 microseconds)

    My initial table has ~ 4.000 entries and 7 columns. The condensed result ~3.000 entries. 

    3 columns has no need to be condensed and i can derive the content from the mem-structure.
    Doing so, the runtime shrinks (45.000 microseconds).

    When playing with the ‘new statements’ i often had the experience, that the codings looks cool, but at the expensive of performance.

     

    Beneath the performance considerations, the pretty printer is not able to format such coding anymore :-(.

    (0) 

Leave a Reply