1. DISPLAY — a representação padrão

Quando você declara PIC 9(05) sem cláusula USAGE, o campo é DISPLAY — cada dígito ocupa exatamente um byte, gravado como caractere EBCDIC (no mainframe) ou ASCII (em ambiente PC/Linux). É o único formato que pode aparecer diretamente em arquivos sequenciais e em tela sem conversão.

COBOL DISPLAY — declaração e comportamento
       WORKING-STORAGE SECTION.

       01  WS-VALOR    PIC 9(05).       *DISPLAY implícito — 5 bytes
       01  WS-VALOR-X  PIC 9(05) DISPLAY. *Explícito — idêntico

             * Para o valor 12345, a memória contém (EBCDIC):
             * F1 F2 F3 F4 F5   (cada dígito = 0xFn)

       01  WS-SIGNED   S9(05).
             * Sinal no nibble alto do último byte:
             * +12345 → F1 F2 F3 F4 C5   (C = positivo)
             * -12345 → F1 F2 F3 F4 D5   (D = negativo)

       01  WS-NOME     X(20).            *Alfanumérico — sempre DISPLAY

✅ Quando usar DISPLAY

  • Campos lidos/gravados em arquivos sequenciais (QSAM, VSAM com registros texto)
  • Campos exibidos em tela CICS sem formatação extra
  • Campos de chave VSAM KSDS (devem ser DISPLAY para comparação direta)
  • Qualquer campo alfanumérico PIC X

2. COMP-3 — Packed Decimal

COMP-3 (também chamado PACKED-DECIMAL) empacota dois dígitos por byte. O último nibble (meio-byte) carrega o sinal: C para positivo, D para negativo, F para não-sinalizado. É o tipo mais usado em COBOL bancário para valores monetários — ocupa metade do espaço de DISPLAY e a UCP do mainframe faz aritmética diretamente em packed via instruções AP/SP/MP/DP, sem converter para binário.

COBOL COMP-3 — declaração e layout de memória
       WORKING-STORAGE SECTION.

       01  WS-SALDO   S9(13)V99 COMP-3.
             * 13 dígitos inteiros + 2 decimais implícitos = 15 dígitos
             * Tamanho: CEIL((15+1)/2) = 8 bytes
             * Fórmula: CEIL((n_digitos + 1) / 2)

       01  WS-TAXA    S9(03)V9(06) COMP-3.
             * 9 dígitos total → 5 bytes

       01  WS-QTDE    S9(07) COMP-3.
             * 7 dígitos → 4 bytes

       PROCEDURE DIVISION.
           MOVE 123456789  TO WS-QTDE
                 * Na memória: 01 23 45 67 8C
                 *              ── ── ── ── ──
                 *              01 23 45 67 = dígitos empacotados
                 *              8C = último dígito (8) + sinal positivo (C)
           COMPUTE WS-SALDO = WS-SALDO * 1.0253
           ADD 100 TO WS-SALDO

🦕 Analogia — dois passageiros por assento

Imagine que cada byte é um assento de avião com duas poltronas (nibbles). No DISPLAY, apenas uma poltrona é usada — a outra carrega sempre o prefixo F. No COMP-3, as duas poltronas são ocupadas com dígitos de verdade. Com 8 bytes, DISPLAY guarda 8 dígitos; COMP-3 guarda 15. O avião está lotado do jeito certo.

Calculando o tamanho em bytes

Fórmula Tamanho de COMP-3
  Bytes = CEIL( (total_de_dígitos + 1) / 2 )

  PIC S9(07)    →  CEIL( (7+1)/2 )  = 4 bytes
  PIC S9(09)    →  CEIL( (9+1)/2 )  = 5 bytes
  PIC S9(13)V99 →  CEIL((15+1)/2 )  = 8 bytes
  PIC S9(15)    →  CEIL((15+1)/2 )  = 8 bytes
  PIC S9(17)    →  CEIL((17+1)/2 )  = 9 bytes   ← máximo prático

⚠️ S0C7 — o abend do COMP-3 não inicializado

Se um campo COMP-3 contém X'00' (não inicializado) e você tenta usá-lo em aritmética ou MOVE para campo numérico, o z/OS gera S0C7 (data exception). Sempre use INITIALIZE ou MOVE ZEROS antes de operar sobre campos COMP-3. Ver artigo Abends e Debugging.

3. COMP / COMP-4 — Binário puro

COMP e COMP-4 são sinônimos. O campo é armazenado em binário big-endian (byte mais significativo primeiro, conforme padrão z/Architecture). O compilador aloca 2 bytes para campos de até 4 dígitos e 4 bytes para campos de 5 a 9 dígitos — independente de quantos dígitos você declarou dentro do limite.

COBOL COMP — tamanhos e uso típico
       WORKING-STORAGE SECTION.

             * 2 bytes — guarda de -32.768 a +32.767 (signed)
       01  WS-IDX        S9(04) COMP.   *subscript de tabela pequena
       01  WS-CONTADOR   S9(04) COMP.   *contador de loop

             * 4 bytes — guarda de -2.147.483.648 a +2.147.483.647
       01  WS-LINHAS     S9(09) COMP.   *contagem de registros
       01  WS-OCORRE-MAX S9(09) COMP.   *limite de OCCURS DEPENDING ON

             * 8 bytes — até 18 dígitos (declara S9(10) a S9(18))
       01  WS-BIG        S9(18) COMP.

       PROCEDURE DIVISION.
           PERFORM VARYING WS-IDX FROM 1 BY 1
                   UNTIL  WS-IDX > 100
               CONTINUE
           END-PERFORM
                 * WS-IDX em COMP: incremento PERFORM sem conversão = rápido

✅ Quando usar COMP

  • Subscripts e índices de OCCURS — o compilador gera código mais enxuto
  • Contadores de loop e acumuladores de quantidade sem casas decimais
  • Campos de interface com rotinas C ou assembler que esperam inteiro binário
  • OCCURS DEPENDING ON — o campo ODO obrigatoriamente deve ser COMP

COMP não trunca como COMP-3

COBOL Comportamento de overflow em COMP
       01  WS-SMALL  S9(04) COMP.   *2 bytes, max +32.767

       PROCEDURE DIVISION.
           MOVE 40000 TO WS-SMALL
                 * PIC 9(04) comportaria apenas 9999, mas COMP aloca 2 bytes
                 * O compilador pode truncar pelo PIC ou permitir overflow
                 * binário (wrap-around) — comportamento depende de TRUNC

             * Opção de compilação TRUNC(BIN) — não trunca pelo PIC,
             * usa capacidade total do campo binário
             * Opção TRUNC(STD) — trunca pelo PIC (padrão ANSI)
             * Opção TRUNC(OPT) — compilador decide o mais rápido

🟣 Opção de compilação TRUNC

A maioria dos shops define TRUNC(OPT) ou TRUNC(BIN) no JCL de compilação. Com TRUNC(BIN), um campo PIC S9(04) COMP pode guardar até 32.767 mesmo que a PIC sugira 9.999. Isso é comum em código legado — sempre confirme a opção usada no seu ambiente antes de assumir que o limite é o PIC.

4. COMP-5 — Native Binary

COMP-5 é binário como COMP, mas usa a ordem de bytes nativa do hardware. No mainframe z/Architecture isso é big-endian — igual a COMP. A diferença aparece em ambiente PC/Linux (little-endian): um campo COMP gravado no mainframe e lido num servidor Intel teria os bytes trocados, gerando valor errado. Com COMP-5, o compilador garante que vai usar a ordem correta para a plataforma.

COBOL COMP-5 — uso em interoperabilidade
       WORKING-STORAGE SECTION.

             * Campos passados para rotinas C em ambiente Linux/PC
       01  WS-INT32   S9(09) COMP-5.   *int  em C — 4 bytes, native
       01  WS-INT16   S9(04) COMP-5.   *short em C — 2 bytes, native
       01  WS-INT64   S9(18) COMP-5.   *long  em C — 8 bytes, native

             * No mainframe z/OS: COMP-5 == COMP (ambos big-endian)
             * Em GnuCOBOL (PC/Linux): COMP-5 gera little-endian
             *                          COMP gera big-endian (diferente!)

💗 No dia a dia do mainframe

Se você trabalha exclusivamente em z/OS e não faz interface com programas C ou Java rodando em servidor separado, pode usar COMP e COMP-5 de forma intercambiável — os dois geram big-endian. A distinção importa quando você está escrevendo código portável ou enviando dados binários para sistemas fora do mainframe.

5. COMP-1 e COMP-2 — Ponto flutuante

COMP-1 é ponto flutuante de precisão simples (4 bytes, equivalente ao float de C). COMP-2 é precisão dupla (8 bytes, equivalente a double). Eles não aceitam cláusula PIC — o tamanho é fixo e determinado pelo tipo.

COBOL COMP-1 e COMP-2 — declaração
       WORKING-STORAGE SECTION.

       01  WS-FLOAT   COMP-1.    *sem PIC — 4 bytes (~7 dígitos significativos)
       01  WS-DOUBLE  COMP-2.    *sem PIC — 8 bytes (~15 dígitos significativos)

       PROCEDURE DIVISION.
           MOVE 3.14159265358979 TO WS-DOUBLE
           COMPUTE WS-DOUBLE = WS-DOUBLE * 2.0
           DISPLAY WS-DOUBLE   *→  6.28318530717958

                 * Funções matemáticas usam COMP-2:
           COMPUTE WS-DOUBLE = FUNCTION SQRT(2)
           COMPUTE WS-DOUBLE = FUNCTION LOG(WS-DOUBLE)
           COMPUTE WS-DOUBLE = FUNCTION SIN(WS-DOUBLE)

⚠️ NUNCA use COMP-1/COMP-2 para valores monetários

Ponto flutuante binário não consegue representar exatamente a maioria das frações decimais. O valor 0.10 (dez centavos) em COMP-1 é aproximadamente 0.10000000149.... Em cálculos repetidos (como juros compostos de milhões de contas), o erro acumula e gera centavos divergentes — o pesadelo de qualquer auditor. Para dinheiro, use sempre COMP-3 com casas decimais explícitas na PIC.

✅ Quando COMP-1/COMP-2 fazem sentido

  • Cálculos científicos ou estatísticos onde precisão relativa importa, não exata
  • Interface com funções intrínsecas matemáticas (SQRT, SIN, LOG, EXP)
  • Passagem de parâmetros para rotinas C que esperam float/double
  • Campos recebidos de sensores ou sistemas externos com ponto flutuante nativo

6. Tabela comparativa

Tipo Sinônimo Representação Tamanho PIC obrigatória Uso principal
DISPLAY (padrão) 1 byte/dígito (EBCDIC/ASCII) n bytes Sim Arquivos, tela, chaves VSAM
COMP-3 PACKED-DECIMAL 2 dígitos/byte + nibble de sinal ⌈(n+1)/2⌉ bytes Sim Valores monetários, totais
COMP COMP-4 / BINARY Binário big-endian 2, 4 ou 8 bytes Sim Subscripts, contadores, ODO
COMP-5 NATIVE-BINARY Binário nativo (big ou little) 2, 4 ou 8 bytes Sim Interop C/Java em multipla plataforma
COMP-1 FLOAT-SHORT IEEE 754 simples (float) 4 bytes fixos Não Cálculos científicos
COMP-2 FLOAT-LONG IEEE 754 dupla (double) 8 bytes fixos Não Funções intrínsecas matemáticas

Comparação de espaço para o mesmo valor

Comparação PIC S9(13)V99 nos diferentes tipos
  Tipo        Bytes   Observação
  ──────────  ──────  ────────────────────────────────────────────
  DISPLAY     15      1 byte por dígito (15 dígitos ao total)
  COMP-3       8      ⌈(15+1)/2⌉ = 8 bytes — 47% menor que DISPLAY
  COMP         8      PIC S9(13) → 8 bytes (entra na faixa 10–18)
  COMP-1       4      mas só ~7 dígitos significativos — INACEITÁVEL
  COMP-2       8      mas arredondamento binário — INACEITÁVEL p/ $

7. Como escolher o tipo certo

Guia Decisão por caso de uso
  Caso de uso                              Tipo recomendado
  ───────────────────────────────────────  ─────────────────
  Campo em registro de arquivo sequencial  DISPLAY
  Chave de pesquisa VSAM KSDS              DISPLAY
  Campo exibido em tela CICS               DISPLAY
  Valor monetário / taxa / saldo           COMP-3
  Subtotal / total acumulado               COMP-3
  Subscript de tabela OCCURS               COMP (S9(04) ou S9(09))
  Campo ODO (OCCURS DEPENDING ON)          COMP
  Contador de registros lidos/gravados     COMP
  Interface com C/assembler (z/OS)         COMP ou COMP-5
  Interface com Java/C em servidor Linux   COMP-5
  Função SQRT, SIN, LOG, EXP              COMP-2
  Campo recebido de sistema com float      COMP-2

💗 Regra de bolso para iniciantes

Dinheiro → COMP-3. Contador/subscript → COMP. Arquivo/tela → DISPLAY. Se você memorizar só isso, vai cobrir 95% dos casos encontrados em sistemas bancários COBOL no dia a dia.

8. Conversões e armadilhas

O compilador converte automaticamente entre os tipos quando você faz MOVE ou aritmética entre campos de tipos diferentes. Mas algumas conversões têm custo ou perigo:

COBOL Conversões implícitas
       WORKING-STORAGE SECTION.
       01  WS-DISP   S9(07).
       01  WS-PACK   S9(07) COMP-3.
       01  WS-BIN    S9(09) COMP.

       PROCEDURE DIVISION.
                 * O compilador gera a conversão necessária em cada MOVE:
           MOVE WS-DISP TO WS-PACK   *DISPLAY → COMP-3: OK, gerado CVB/PACK
           MOVE WS-PACK TO WS-BIN    *COMP-3 → COMP: OK, gerado UNPK/CVB
           MOVE WS-BIN  TO WS-DISP   *COMP → DISPLAY: OK, gerado CVD/UNPK

                 * ARITMÉTICA mista — o compilador escolhe o tipo interno
           COMPUTE WS-PACK = WS-PACK + WS-BIN
                 * Internamente: converte WS-BIN para packed, soma em packed
                 * Mais eficiente manter os dois como COMP-3 se soma é frequente

Reinterpretação de bytes com REDEFINES

REDEFINES sobrepõe o mesmo espaço de memória com uma PIC diferente — sem conversão. Isso é útil para inspecionar o conteúdo bruto de um campo binário, mas perigoso se os tipos são incompatíveis:

COBOL REDEFINES para inspecionar bytes — uso de diagnóstico
       WORKING-STORAGE SECTION.
       01  WS-VALOR-PACK   S9(07) COMP-3.    *4 bytes
       01  WS-VALOR-HEX    X(04)
                         REDEFINES WS-VALOR-PACK.

       PROCEDURE DIVISION.
           MOVE 1234567 TO WS-VALOR-PACK
           DISPLAY 'HEX: ' WS-VALOR-HEX
                 * Exibe os 4 bytes brutos: 01 23 45 6C
                 * 01 23 45 = dígitos   6C = último dígito (6) + sinal positivo (C)

             * ⚠️ NUNCA faça aritmética em WS-VALOR-HEX —
             *   ele é X, não numérico. Use só para DISPLAY de diagnóstico.

Alinhamento de estruturas com SYNCHRONIZED

COBOL SYNCHRONIZED — alinhamento de campos COMP em estrutura
       01  WS-REGISTRO.
           05  WS-FLAG    X(01).
           05  WS-CONTA   S9(09) COMP SYNCHRONIZED.
                 * Sem SYNC: WS-CONTA começa no byte 2 — não alinhado em word
                 * Com SYNC: compilador insere 3 bytes de padding para alinhar
                 *           WS-CONTA no próximo limite de doubleword (byte 4)
                 * No z/Architecture, COMP não alinhado ainda funciona (sem exceção),
                 * mas SYNC pode melhorar performance em loops intensos.

9. Exemplo completo

O sub-programa CALCJURO recebe capital, taxa mensal e prazo, calcula juros compostos e devolve o montante final e os juros devidos. Demonstra o uso correto de cada tipo de dado no mesmo programa:

COBOL CALCJURO — juros compostos com tipos mistos
      *----------------------------------------------------------------
      * CALCJURO — calcula montante por juros compostos
      * Interface: CAPITAL IN, TAXA-MES IN, PRAZO-MESES IN
      *            MONTANTE OUT, JUROS OUT
      *----------------------------------------------------------------
       IDENTIFICATION DIVISION.
           PROGRAM-ID. CALCJURO.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

             * Acumulador interno — COMP-2 para cálculo científico (potência)
       01  WS-FATOR      COMP-2.     *(1 + taxa)^prazo — ponto flutuante
       01  WS-TAXA-PERC  COMP-2.     *taxa convertida p/ decimal (ex: 0.0253)
       01  WS-RESULT-FLT COMP-2.     *resultado em float antes de arredondar

             * Contador do loop — COMP
       01  WS-MES-ATUAL  S9(04) COMP.

       LINKAGE SECTION.
       01  LK-CAPITAL    S9(13)V99 COMP-3.   *moeda — COMP-3
       01  LK-TAXA-MES   S9(03)V9(06) COMP-3. *ex: 0.025300
       01  LK-PRAZO      S9(04) COMP.         *contador — COMP
       01  LK-MONTANTE   S9(13)V99 COMP-3.   *resultado — COMP-3
       01  LK-JUROS      S9(13)V99 COMP-3.   *resultado — COMP-3

       PROCEDURE DIVISION USING
               LK-CAPITAL LK-TAXA-MES LK-PRAZO
               LK-MONTANTE LK-JUROS.

       0000-PRINCIPAL.
                 * Converte taxa COMP-3 → COMP-2 para usar FUNCTION POWER
           MOVE LK-TAXA-MES           TO WS-TAXA-PERC
           COMPUTE WS-FATOR =
               FUNCTION POWER(1.0 + WS-TAXA-PERC, LK-PRAZO)
                 * Resultado em float → converte de volta para COMP-3
           COMPUTE WS-RESULT-FLT =
               LK-CAPITAL * WS-FATOR
                 * Arredonda para 2 casas e grava em COMP-3
           COMPUTE LK-MONTANTE ROUNDED = WS-RESULT-FLT
           COMPUTE LK-JUROS    = LK-MONTANTE - LK-CAPITAL
           GOBACK.

🦕 A estratégia de "ponte flutuante"

O exemplo usa COMP-2 apenas como ponte interna para a função POWER (que precisa de ponto flutuante), e depois converte o resultado de volta para COMP-3 com ROUNDED. Isso garante que o resultado final seja exato na segunda casa decimal — o mundo do float fica contido dentro do sub-programa e não vaza para o chamador.

10. Erros comuns

1. COMP-1/COMP-2 para campo monetário

COBOLErro clássico de ponto flutuante
             * ❌ ERRADO — ponto flutuante perde centavos
       01  WS-SALDO-ERRO  COMP-1.

       PROCEDURE DIVISION.
           MOVE  1000000.10 TO WS-SALDO-ERRO
           DISPLAY WS-SALDO-ERRO   *→ 1000000.12 (!!!) — imprecisão de float

             * ✅ CORRETO — COMP-3 preserva exatamente os centavos
       01  WS-SALDO-OK    S9(13)V99 COMP-3.

           MOVE 1000000.10 TO WS-SALDO-OK
           DISPLAY WS-SALDO-OK     *→ 100000010 (com V99 implícito = 1000000.10)

2. COMP-3 sem inicialização → S0C7

COBOLS0C7 por campo não inicializado
       01  WS-TOTAL  S9(11)V99 COMP-3.   *conteúdo inicial: X'00..00'

       PROCEDURE DIVISION.
                 * ❌ ADD sem inicializar → S0C7
           ADD WS-VALOR TO WS-TOTAL

                 * ✅ Inicializa antes de acumular
           INITIALIZE WS-TOTAL
           ADD WS-VALOR TO WS-TOTAL

3. Usar COMP em campo de arquivo

COBOLCampo binário em registro — leitura errada
             * ❌ Se o arquivo é texto fixo (DISPLAY), declarar COMP lê lixo
       FD  ARQ-CLIENTES RECORD CONTAINS 100 CHARACTERS.
       01  REG-CLI.
           05  CLI-SALDO    S9(13)V99 COMP-3.
                 * Se o arquivo foi gravado em DISPLAY, os 8 bytes lidos
                 * como COMP-3 resultam em S0C7 ou valor absurdo.

             * ✅ Use o mesmo tipo com que o arquivo foi gravado.
             *    Se vier de outro sistema, consulte o copybook de layout.

4. S9(05) COMP guardando valor > 9999 sem TRUNC(BIN)

COBOLTruncamento dependente de opção de compilação
       01  WS-CNT  S9(04) COMP.   *2 bytes = até 32.767 em binário
                                       *        = até  9.999 pela PIC

       PROCEDURE DIVISION.
           MOVE 15000 TO WS-CNT
                 * Com TRUNC(STD): WS-CNT = 5000 (truncou pelo PIC = 4 dígitos)
                 * Com TRUNC(BIN): WS-CNT = 15000 (usa capacidade do binário)
                 * Solução segura: declarar PIC compatível com o valor esperado
                 *   S9(09) COMP para até 2.147.483.647 sem ambiguidade

5. REDEFINES misturando DISPLAY e COMP-3

COBOLREDEFINES de tipo incompatível
       01  WS-CAMPO-X    X(08).
       01  WS-CAMPO-NUM  S9(13)V99 COMP-3
                         REDEFINES WS-CAMPO-X.
             * ⚠️ Tamanhos COINCIDEM (8 bytes), mas se WS-CAMPO-X
             *    contém texto EBCDIC (F1 F2...), lido como COMP-3
             *    gerará S0C7 ao tentar aritmética.
             * Use REDEFINES de COMP-3 sobre X apenas para diagnóstico,
             * nunca para operação de produção.