COBOL : COMPUTE ROUNDED

Une petite notion de COBOL pour par exemple trouver quelques centimes par ci, quelques centimes par là.

Il s’agit de l’utilisation du paramètre ROUNDED dans l’écriture d’un COMPUTE

Les variables

01 W-NOMBRE1 PIC S9(15)V99 COMP-3.
01 W-NOMBRE2 PIC S9(15)V99 COMP-3.
01 W-MULTIPLICATEUR PIC S9(3)V9(6) COMP-3.
01 W-RESULTAT1 PIC S9(15)V99 COMP-3.
01 W-RESULTAT2 PIC S9(15)V99 COMP-3.
01 W-EDIT9 PIC +ZZZ.ZZZ.ZZZ.ZZZ.ZZ9,99.

Le code d’exemple

DISPLAY '----------ROUNDED DEBUT -------------'
MOVE 123,12 TO W-NOMBRE1
MOVE 567,56 TO W-NOMBRE2
MOVE 456,456789 TO W-MULTIPLICATEUR
MOVE 0 TO W-RESULTAT1
MOVE 0 TO W-RESULTAT2

COMPUTE W-RESULTAT1 ROUNDED = W-NOMBRE1
* W-NOMBRE2
* W-MULTIPLICATEUR

COMPUTE W-RESULTAT2 = W-NOMBRE1
* W-NOMBRE2
* W-MULTIPLICATEUR

MOVE W-RESULTAT1 TO W-EDIT9
DISPLAY 'ROUNDED    : ' W-EDIT9

MOVE W-RESULTAT2 TO W-EDIT9
DISPLAY 'NOT ROUNDED: ' W-EDIT9

MOVE 0 TO W-RESULTAT1
MOVE 0 TO W-RESULTAT2

COMPUTE W-RESULTAT1 ROUNDED = W-NOMBRE1
* W-NOMBRE2
- W-MULTIPLICATEUR

COMPUTE W-RESULTAT2 = W-NOMBRE1
* W-NOMBRE2
- W-MULTIPLICATEUR

MOVE W-RESULTAT1 TO W-EDIT9
DISPLAY 'ROUNDED    : ' W-EDIT9

MOVE W-RESULTAT2 TO W-EDIT9
DISPLAY 'NOT ROUNDED: ' W-EDIT9

DISPLAY '----------ROUNDED FIN -------------'

La sysout

----------ROUNDED DEBUT -------------
ROUNDED    : + 31.896.281,66
NOT ROUNDED: + 31.896.281,65
ROUNDED    : + 69.421,53
NOT ROUNDED: + 69.421,53
----------ROUNDED FIN -------------

Résultats réels

Pour le premier calcul : 31.896.281,6590951

Pour le second : 69421,530411

Conclusion

Comme l’explique la documentation Cobol, ROUNDED arrondi la dernière décimale en l’augmentant de 1 si la décimale suivante en trop dépasse ou est égale à 5. Vrai dans le premier calcul faut dans le second.

Notez que le comportement normal est la troncature des décimaux en trop par rapport à la variable de réception du COMPUTE.

Performance entre compute et move

 WORKING-STORAGE SECTION.
 01 WORKING-VAR.
    05 W-TAU-3-6         PIC S9(3)V9(6) COMP-3.
    05  W-TAU-2-5        PIC S9(2)V9(5).
    05 W-CPT             PIC 9(09).

 PROCEDURE DIVISION.
    move 123,123456       to W-TAU-3-6
    move 12,12345         to W-TAU-2-5

    perform until W-CPT = 999999999
*      compute W-TAU-3-6 = W-TAU-2-5
       move W-TAU-2-5     to W-TAU-3-6
       add 1              to W-CPT
    end-perform

Aujourd’hui, j’ai voulu savoir ce qui est le mieux à utiliser entre un compute et un move pour renseigner un champ. J’ai donc exécuter le petit bout de code si dessus.
Résultats :

Temps d’exécution Temps CPU
Move 45.49 1,814
35.9 1,81
1.05.83 1,818
Compute 49.44 2,429
38.66 2,421
1.16.26 2,441

Après 3 exécutions de chaque on distingue bien que le compute mange beaucoup plus de CPU que le move pour le même résultat (Ici environ 1/4 de plus). Conclusion, utiliser les compute seulement en cas de calcul et non pour renseigner une variable.

Mise à jour après un second test qui met sur un pied d’égalité le compute et le move (2.500 Temps CPU pour les deux) :

compute W-TAU-2-5 = W-TAU-3-6
move W-TAU-3-6 to W-TAU-2-5

Dans le cas où l’on met une zone plus grande dans une zone plus petite le compute et le move on les mêmes performances, avec une petite préférence personnelle pour le compute qui évite quelques Warning dans ce cas bien précis.

Manipulations de données simples

Des cas simples, toujours bon à avoir sous la main, ou ici plus particulièrement sous les yeux et à portée d’internet !
Dans cet article je vais parler de quelques bases de manipulations de données en Cobol:

 WORKING-STORAGE SECTION.
    01 WORKING-VAR.
       05 W-SOLDMOYEN-15-2 PIC S9(15)V9(2) COMP-3.
       05 W-SOLDMOYEN-17   PIC S9(17) COMP-3.

 PROCEDURE DIVISION.
    display 'Variables non renseignées :'
    display '15-2 :' W-SOLDMOYEN-15-2
    display '17 :'   W-SOLDMOYEN-17

    move 12,34 to W-SOLDMOYEN-15-2
    move 1234 to W-SOLDMOYEN-17
    display 'Variables renseignées :'
    display '15-2 :' W-SOLDMOYEN-15-2
    display '17 :'   W-SOLDMOYEN-17

    move W-SOLDMOYEN-15-2 to W-SOLDMOYEN-17
    display 'Variables après passage de 15-2 à 17 :'
    display '15-2 :' W-SOLDMOYEN-15-2
    display '17 :'   W-SOLDMOYEN-17

    compute W-SOLDMOYEN-17 = W-SOLDMOYEN-15-2 * 100
    display 'Variables après multiplic. de 15-2 par 100 à 17 :'
    display '15-2 :' W-SOLDMOYEN-15-2
    display '17 :'   W-SOLDMOYEN-17

    * Les deux techniques suivantes marchent :
    move  W-SOLDMOYEN-17  to W-SOLDMOYEN-15-2 
    * ... laquelle des deux est la meilleure ?
    compute W-SOLDMOYEN-15-2 = W-SOLDMOYEN-17
    display 'Variables après passage de 17 à 15-2 :'
    display '15-2 :' W-SOLDMOYEN-15-2
    display '17 :'   W-SOLDMOYEN-17

    move 12345678901234567 to W-SOLDMOYEN-17
    compute W-SOLDMOYEN-15-2 = W-SOLDMOYEN-17
    display 'Variable 15-2 après compute de 12345678901234567 :'
    display '15-2 :' W-SOLDMOYEN-15-2
    display '17 :'   W-SOLDMOYEN-17

Ce qui nous donne en sortie :

Variables non renseignées :
15-2 :00000000000000000
17   :00000000000000000
Variables renseignées :
15-2 :00000000000001234
17   :00000000000001234
Variables après passage de 15-2 à 17 :
15-2 :00000000000001234
17   :00000000000000012
Variables après multiplic. de 15-2 par 100 à 17 :
15-2 :00000000000001234
17   :00000000000001234
Variables après passage de 17 à 15-2 :
15-2 :00000000000123400
17   :00000000000001234
Variable 15-2 après compute de 12345678901234567 :
15-2 :34567890123456700
17   :12345678901234567 

Voilà pour les manipulations du jour, le but étant de retrouver facilement quelles actions donne quels résultats en étant sûr des données et ne pas avoir à retaper un cas de test ou de faire des displays abusifs ;)