quinta-feira, 27 de agosto de 2009

Combinação de valores Base-2.


Combinação de valores Base 2 é bastante utilizado em "campos" onde precisamos guardar uma combinação de "possibilidades" ou opções em um único campo. Por exemplo em campos de status ou pendencias.


O valor resultante desta combinação único, nenhuma outra combinação resulta no mesmo valor, então com uma lógica simples é possivel achar essa combinação.


Um exemplo disso são os campos Status e Status2 da tabela sys.databases ( http://msdn.microsoft.com/pt-br/library/ms179900.aspx )


Select Name, Status, Status2 from Master.dbo.sysdatabases


Name Status Status2
---------- ----------- -----------
master 65544 1090520064


O Status 65544 é a combinação de 65536 e 8
O Status2 1090520064 é a combinação de 1073741824, 16777216 e 1024

De qualquer forma, a sequencia é sempre número anterior * 2, ou em base-2: 2^n.

2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, etc, etc, etc.....

Seguindo o exemplo de "pendências", para facilitar vamos imagina um caso onde um cliente fez um cadastro em uma loja para contratar um financiamento, e está "devendo" alguns documentos para terminar o processo do financiamento:

Código Valor Descrição
1 2 Falta RG
2 4 Falta CPF
3 8 Falta Certidão de Nascimento
4 16 Falta Certidão de Casamento
5 32 Falta Certidão Negativa
6 64 Falta Comprovante de Renda
7 128 Falta Comprovante de Residencia
8 256 Falta Reservista
9 512 Falta Passaporte
10 1024 Falta Comprovante de Votação

Combinando os valores 3 (8), 5 (32), 7 (128), 8 (256) e 10 (1024) = 1448
Ainda faltam para o cliente:
- Falta Certidão de Nascimento
- Falta Certidão Negativa
- Falta Comprovante de Residencia
- Falta Reservista
- Falta Comprovante de Votação

Uma forma simples de se fazer isso é, sabendo que a soma dos números anteriores nunca é maior ou igual à atual, fazer um loop decrescente "easy cake" diminuindo do resultado final +/- assim:


/************************************************************************************************/
Declare @Numero float, @LimiteSuperior float, @iLimiteSuperior Int

Set @Numero = 1448

Set @LimiteSuperior = 562949953421312 -- 49 opções se precisar mais que isso é só calcular.

Set @iLimiteSuperior = 49

Declare @Resultados table (Base int, Valor float)
While @Numero > 0
Begin
If @LimiteSuperior < = @Numero Begin

Insert Into @Resultados Values (@iLimiteSuperior, @LimiteSuperior)
Set @Numero = @Numero - @LimiteSuperior

End

Set @LimiteSuperior = @LimiteSuperior / 2 --Acha o valor anterior
Set @iLimiteSuperior = @iLimiteSuperior - 1

End

Select * from @Resultados

/************************************************************************************************/

Outra forma, que eu acho mais interessante, tambem é um loop decrescente, porem trabalhamos com Log Base-2 que conseguimos com a divisão: LOG(Numero)/LOG(2).

/************************************************************************************************/
Declare @Numero float, @Expoente float
Declare @Resultados table (Base int, Valor float)

Set @Numero = 1448

While @Numero > 0
Begin

Set @Expoente = FLOOR(LOG(@Numero)/LOG(2))
Insert Into @Resultados Values (@Expoente, POWER(cast(2 as float), @Expoente))
set @Numero = @Numero - POWER(cast(2 as float), @Expoente)

End

Select * from @Resultados

Um comentário: