Pessoal eu to calculando digito validador, e em um unico for, eu posso calcular os 2 ou mais digitos de um vez.
Porem quando o 1° digito é invalido, não se faz necessario calcular o segundo, e assim por diante… mais em termos de performance, percorrer 2x ou mais um for e testar c é valido a primeira e c não for não entrar no segundo for, e assim por diante, é mais vantajoso que fazer 1 unico for, e nele fazer a conta dos 2 digitos, ou mais, simultaneamente?
Atualmente eu esotou percorredo o for, e fazendo os calculos simultaneamente, mais ão sei c isso vai dar problema de performance.
sei que muita gente vai pedir, trechos de códigos pra entender a questão, então vai abaixo, só que o trecho ta uma PORCARIA pra ler, estou ate refactorando pra melhorar a leitura…
A quem quiser ler o código, eu tenho uma interface, que funciona para prover os digitos de uma forma mais facil ao código
private interface DigitSequence {
/**
* Recupera o digito do indice pedido, caso o indice esteja OutOfRange retorna
* zero, sem gerar exceções.
* @param index indice do valor buscado.
* @return número de indice index
*/
public int getNumberAt(int index);
/**
* Dimensão desta sequencia de digitos
* @return Dimensão desta sequencia de digitos
*/
public int length();
}
Antes de ler o restante do código é bom saber como funciona os calculos de validadores de CPF, CNPJ, Inscrições estaduais e etcs…
Em sintese todos eles tem um número basico, o numero que realmente conta, e digitos verificadores… a conta é bem simples…
cada digito verificador, é calculado multiplicando um peso especifico por cada digito do numero basico, depois usa-se um divisor para encontrar o digito.
Para o CPF existem 9 numeros baiscos os outros 2 são digitos verificador “209.749.249-53” portanto 209749249 é o número do CPF e 53 é a verificação.
Os pesos para calcular os digitos são
10,9,8,7,6,5,4,3,2 para o 1° digito … ou seja… deve-se somar 10x2 + 9x0 + 8x9 + … 9x2
11,10,9,8,7,6,5,4,3,0 para o 2° digito … note que o 2° digito tem um número a mais de peso, pois ele é multiplicado depois que acha-se o 1° digito verificador, no caso do CPF esse peso é 0, portanto é indiferente o resultado do 1° digito verificador.
O divisor pra o CPF é 11, portanto deve-se pegar a soma acima para cada digito, divir por 11, pegar o resto desta operação e fazer a conta 11-(esse resto) … e esse sera o digito verificador, salvo quando essa conta é maior que 9 e neste caso o digito passa a ser 0.
o CNPJ segue a mesma logica, porem os pesos são
5,4,3,2,9,8,7,6,5,4,3,2 para o 1° digito
6,5,4,3,2,9,8,7,6,5,4,3,2 para o 2° digito (note que para o CNPJ o resultado do 1° digito pesa na conta do 2°)
exemplos de uso
[code]//exemplo de uso para CPF
int[] c1 = {10,9,8,7,6,5,4,3,2}; //pesos do 1° digito do CPF
int[] c2 = {11,10,9,8,7,6,5,4,3}; //pesos do 2° digito do CPF, o ultimo peso 0 não precisa ser escrito, basta ver a interface DigitSequence para ver que qualquer número que se pegue além dos enumerados retornará 0.
int[][] c = {c1,c2}; //array de coeficientes
System.out.println( //Cpf tem 9 números basicos e o divisor é 11
VerifyDigit.isValid(“209.749.249-53”, 9, 11, c));
//exemplo de uso para CNPJ
System.out.println( //Cnpj tem 12 números basicos e o divisor é 11
VerifyDigit.isValid(“11.111.111/0001-81”, 12, 11, “543298765432”,“6543298765432”));
//como CNPJ usa numeros menores que 10 como peso, da pra passar todos os pesos em uma string ^^
[/code]
A sequencia para validação esta abaixo, O método isValid() tem varias formas de entrada, e todas converte para o modo privado mostrado abaixo
onde as entradas de sequencia de digitos são convertidas para interface DigitSequence
/**
* Verifica se a sequencia de digitos <tt>validate</tt>, que tem dimensão basica
* <tt>baseLength</tt> (o restante é digitos verificadores), onde cada digito
* verificador utiliza o <tt>divisor</tt> e os pesos enviado na array de
* {@link DigitSequence}[] <tt>coeficients</tt>
* @param validate sequencia de digitos a ser validada.
* @param baseLength dimensão basica da sequencia de digitos (por exemplo o CPF tem
* dimensão basica = 9 os outros 2 são digitos verificadores).
* @param divisor o divisor do teste dos digitos, por exemplo o CPF usa divisor 11
* @param coeficients uma array de DigitSequence com os pesos para cada digito
* por exemplo para o CNPJ a array é<tt>
* <BR>coeficients = {@link DigitSequence}[2];
* <BR>coeficients[0] = new {@link ArrayInteger}({5,4,3,2,9,8,7,6,5,4,3,2});
* <BR>coeficients[1] = new {@link StringInteger}("6543298765432");
* </tt>
* @return <tt>true</tt> caso a sequencia de digitos contenha os verificadores
* corretos, e <tt>false</tt> caso contrario.
*/
private static boolean isValid(DigitSequence validate,int baseLength, int divisor,
DigitSequence ... coeficients ) {
boolean result = false;
int[] sum = new int[coeficients.length];
/* faz a 1° parte da soma para todos os digitos simultaneamente, ate o final
* dos digitos basicos. */
for (int i = 0 ; i < baseLength ; i++) {
int number = validate.getNumberAt(i);
for (int j = 0 ; j < coeficients.length ; j++) {
sum[j] += number * coeficients[j].getNumberAt(i);
}
}
int[] digit = new int[coeficients.length];
boolean needTeste = true;
int cursor = 0;
/* Calcula cada digito verificador e já testa c ele bate com o enviado, caso
* não sejam iguais, já para o teste e retorna falso, caso ainda exista mais
* teste, após calcular um digito, já realiza as somas para os digitos seguintes
* que esperavam por esse resultado, para multiplicar pelos respectivos pesos.
*/
while (needTeste) {
digit[cursor] = divisor - (sum[cursor]%divisor);
if (digit[cursor] > 9)
digit[cursor] = 0;
result = validate.getNumberAt(baseLength + cursor) == digit[cursor];
cursor++;
if (cursor + baseLength == validate.length() || !result)
needTeste = false;
else {
for (int j = cursor ; j < coeficients.length ; j++) {
sum[j] += digit[cursor-1] * //digito recem calculado
coeficients[j].getNumberAt(baseLength + cursor -1); //peso
}
}
}
return result;
}