%DEC
Convertir en décimal empaqueté
Convertit un texte, une date, une heure ou un nombre en décimal empaqueté, avec le nombre de chiffres et de décimales choisis. Les décimales en trop sont coupées, pas arrondies.
Syntaxe
%DEC(expression : chiffres : décimales)
%DEC(date-heure : format)
expression- Ce qu'il faut convertir : une zone caractère (fixe ou variable) qui contient un nombre écrit en clair, une zone ou une expression numérique.
chiffres- Nombre total de chiffres du résultat. Une constante, connue à la compilation.
décimales- Nombre de chiffres après la virgule dans le résultat. Une constante, elle aussi.
format- Pour une date, une heure ou un horodatage seulement : le format dans lequel on lit la valeur comme un nombre (
*ISO,*EUR…). Le nombre obtenu a l'ordre et les chiffres de ce format, sans séparateur. - Résultat
- Un nombre décimal empaqueté ayant exactement les chiffres et décimales demandés. Les décimales en trop sont supprimées, sans arrondi.
À quoi ça sert
Dès qu'une donnée arrive sous forme de texte (zone saisie à l'écran, colonne d'un fichier CSV, paramètre d'une commande), il faut la transformer en nombre avant de calculer. %DEC le fait en une expression, sans zone de travail intermédiaire et sans MOVE.
La fonction sert aussi à fixer la précision d'un calcul : on choisit le nombre de décimales du résultat, et on sait que le surplus est supprimé. Si c'est un arrondi qu'on veut, on prend %DECH.
Exemple 1 : Texte, date et troncature
**free
// %DEC : convertir en decimal empaquete (texte, date, nombre) - la valeur est TRONQUEE.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-s saisie varchar(12) inz('1250.75');
dcl-s saisie2 varchar(12) inz(' 42 ');
dcl-s saisie3 varchar(12) inz('-3.5');
dcl-s saisie4 varchar(12) inz('1250,75');
dcl-s prix packed(9:4) inz(12.9876);
dcl-s jour date inz(d'2026-09-30');
dcl-s montant packed(9:2);
montant = %dec(saisie : 9 : 2);
snd-msg 'Texte 1250.75 : [' + %char(montant) + ']';
snd-msg 'Texte avec blancs : [' + %char(%dec(saisie2 : 9 : 2)) + ']';
snd-msg 'Texte negatif : [' + %char(%dec(saisie3 : 9 : 2)) + ']';
snd-msg 'Texte avec virgule : [' + %char(%dec(saisie4 : 9 : 2)) + ']';
snd-msg 'Date en nombre : [' + %char(%dec(jour : *iso)) + ']';
snd-msg 'Date *EUR : [' + %char(%dec(jour : *eur)) + ']';
snd-msg '12.9876 en (9:2) : [' + %char(%dec(prix : 9 : 2)) + ']';
snd-msg '12.9876 en (9:0) : [' + %char(%dec(prix : 9 : 0)) + ']';
snd-msg '-12.9876 en (9:0) : [' + %char(%dec(-prix : 9 : 0)) + ']';
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Texte 1250.75 : [1250.75]
Texte avec blancs : [42.00]
Texte negatif : [-3.50]
Texte avec virgule : [1250.75]
Date en nombre : [20260930]
Date *EUR : [30092026]
12.9876 en (9:2) : [12.98]
12.9876 en (9:0) : [12]
-12.9876 en (9:0) : [-12]
Le texte peut contenir des blancs autour (' 42 ' donne 42,00) et un signe moins. Notez la virgule : '1250,75' est acceptée et donne 1250,75, comme si c'était un point.
Une date lue avec *ISO devient 20260930, avec *EUR elle devient 30092026 : c'est l'ordre du format qui compte. Enfin, 12,9876 mis en (9:2) donne 12.98, et -12,9876 mis en (9:0) donne -12 : la coupure se fait vers zéro.
Exemple 2 : Texte invalide et débordement
**free
// %DEC : ce qui se passe avec un texte invalide ou une valeur trop grande.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-ds pgmsts psds qualified;
typ char(3) pos(40);
num char(4) pos(43);
end-ds;
dcl-s saisie varchar(12);
dcl-s montant packed(5:2);
dcl-s gros packed(15:0) inz(5000000000);
monitor;
saisie = '12x';
montant = %dec(saisie : 5 : 2);
on-error *all;
snd-msg 'Texte 12x : statut ' + %char(%status) + ' (' + pgmsts.typ + pgmsts.num + ')';
endmon;
monitor;
saisie = '1.250,75';
montant = %dec(saisie : 5 : 2);
on-error *all;
snd-msg 'Texte 1.250,75 : statut ' + %char(%status) + ' (' + pgmsts.typ + pgmsts.num + ')';
endmon;
monitor;
saisie = '';
montant = %dec(saisie : 5 : 2);
on-error *all;
snd-msg 'Texte vide : statut ' + %char(%status) + ' (' + pgmsts.typ + pgmsts.num + ')';
endmon;
monitor;
saisie = '123456';
montant = %dec(saisie : 5 : 2);
on-error *all;
snd-msg 'Texte 123456 : statut ' + %char(%status) + ' (' + pgmsts.typ + pgmsts.num + ')';
endmon;
monitor;
montant = %dec(gros : 5 : 2);
on-error *all;
snd-msg 'Nombre 5 Md : statut ' + %char(%status) + ' (' + pgmsts.typ + pgmsts.num + ')';
endmon;
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Texte 12x : statut 105 (RNX0105)
Texte 1.250,75 : statut 105 (RNX0105)
Texte vide : statut 105 (RNX0105)
Texte 123456 : statut 103 (RNX0103)
Nombre 5 Md : statut 103 (MCH1210)
Un texte qui n'est pas un nombre plante le programme : statut 105, message RNX0105. C'est le cas pour '12x', pour une chaîne vide et pour '1.250,75' (point de milliers et virgule décimale mélangés). Un résultat qui ne tient pas dans les chiffres demandés donne RNX0103 (pour '123456' en (5:2)) ou MCH1210 (pour un nombre trop grand).
Le bloc monitor avec on-error *all attrape ces erreurs ; %status donne le statut et la structure d'état du programme (psds) l'identifiant du message.
Le piège
Un texte invalide n'est pas converti en zéro : il plante le programme. Une saisie vide, une lettre, un séparateur de milliers avec virgule décimale ('1.250,75') : tout cela donne RNX0105. Toujours entourer un %DEC sur une saisie utilisateur par un monitor, ou contrôler le texte avant avec %CHECK.
Deuxième surprise : les décimales sont coupées. Le prix 12,9876 devient 12,98 et non 12,99. Pour arrondir, utiliser %DECH.