4 de novembro de 2008

Modulus 11


Modulus 11 (mod11) é um algoritmo para criar um dígito de verificação baseado numa sequência de números pré determinada. Ele é bastante parecido com o Algoritmo de Luhn, com a diferença de que usa pesos para multiplicar cada dígito da sequência. Estes pesos variam de 2 a n, onde n pode variar de aplicação para aplicação.

Diferentemente do algoritmo de Luhn, é difícil encontrar informações precisas sobre o mod11 e suas implementações variam bastante de programador para programador. Uma boa implementação que eu encontrei, foi a da HP:
  1. Tome uma sequência de números.
  2. Começando da última posição, multiplique o item por 2 e adicione o resultado ao somatório, que deve iniciar com 0.
  3. Repita o passo 2 para os outros itens da sequência, lembrando de incrementar em 1 o fator multiplicador (quando este for maior que o valor máximo de multiplicação, deve ser reiniciado com o valor 2).
  4. Divida o somatório por 11 e considere o resto da divisão.
  5. Subtraia de 11, o valor obtido no passo 4 e o resultado será o dígito de verificação.

Apesar de parecer perfeito à primeira vista, o algoritmo apresentado possui duas falhas. Caso o resultado do passo 4 for 0 ou 1, o resultado do passo 5 será 11 ou 10, respectivamente. Isto contraria a idéia do dígito de verificação ser um número entre 0 e 9.

Segundo a implementação da HP, um resultado 10 significa que a sequência de números é inválida para utilização com o algoritmo. Já um resultado 11 implica que a saída do algoritmo é 0. Seria relativamente fácil implementar esta solução, mas isto significaria que muitos números não poderiam ser usados com este algoritmo.

Para quem não sabe, muitos documentos brasileiros utilizam o mod11 para cálculo dos seus dígitos verificadores, como o CPF, CNPJ e Título de Eleitor, além de códigos mais diversos, como o código de procedimentos do SUS (Sistema Único de Saúde). Sendo assim, era preciso adaptar o algoritmo para trabalhar com qualquer saída, tratando-a.

A solução que eu encontrei foi:
  1. Tome uma sequência de números.
  2. Começando da última posição, multiplique o item por 2 e adicione o resultado ao somatório, que deve iniciar com 0.
  3. Repita o passo 2 para os outros itens da sequência, lembrando de incrementar em 1 o fator multiplicador (quando este for maior que o valor máximo de multiplicação, deve ser reiniciado com o valor 2).
  4. Subtraia de 11, o resto da divisão do somatório por 11.
  5. Se o resultado obtido no passo 4 for maior que 9, o dígito verificador será 0. Senão, o dígito verificador será o próprio resultado do passo 4.

Como pode ser percebido, a diferença do segundo, para o primeiro algoritmo apresentado é que, em vez de descartar uma sequência de números cujo dígito verificador dê 10, o segundo retorna o valor 0 para o mesmo. Isto garante que o mesmo funcionará para qualquer sequência de números.

Com a implementação do algoritmo mod11 como uma função separada, fica fácil calcular os dígitos verificadores de quaisquer documentos que o utilizem, tornando os códigos mais limpos e aumentando a reusabilidade de código. Para concluir, segue abaixo a implementação deste algoritmo feita por mim em Python.

# Modulus 11
#
# AUTHOR: Jose Lopes de Oliveira Junior
#             http://versaopropria.blogspot.com
#             jlojunior _at_ gmail _dot_ com
#
# DATE: 2008/10/27
#
# LICENCE: GPLv3 - http://www.gnu.org/licenses/gpl.html
#
# DESCRIPTION: Implements Modulus 11 check digit algorithm
# +as a function. See the docstring for more details.

def mod11(list, max_weight=7):

    """Implements Modulus 11 check digit algorithm.

    It's a variation of the HP's Modulus 11 algorithm.
    Requires the sequence to be calculated in a list of
    integers.
    The HP's Modulus 11 algorithm can be accessed through
    the following link:
    http://docs.hp.com/en/32209-90024/apds02.html

    """

    sum = 0
    weight = 2

    # Iterates through the list from right to left,
    # +multiplying each value for it's weight. If
    # +the weight reaches max_weight, then it is
    # +restarted to 2.
    for item in reversed(list):
        sum += item * weight
        weight += 1

        if weight > max_weight:
            weight = 2

    mod = 11 - sum % 11

    # HP's Modulus 11 algorithm says that a 10
    # +result is invalid and a 11 result is equal
    # +to 0. So, both values are returned as 0.
    if mod > 9:
        return 0

    else:
        return mod
Código 1. Modulus 11 em Python.



Leia Também

Nenhum comentário:

Postar um comentário