Ponto flutuante em micro controladores, como?

Li-po, Li-Ion, Nimh, 1s2p, 10c...... quer aprender mais sobre o "combustivel" dos nossos modelos? Este é o local! Aqui também está aqueles esquema de carregador ou aquele ESC que estava procurando.
Avatar do usuário
-=|Novelli|=-
Equipe E-voo.com
Mensagens: 2043
Registrado em: Seg Nov 10, 2003 3:06 pm
Localização: São Paulo SP

Ponto flutuante em micro controladores, como?

Mensagem por -=|Novelli|=- »

Pessoal,

estou desenvolvendo uma aplicação que precisa executar um calculo envolvendo ponto flutuante. O problema é que eu sei que microcontroladores de 8bits possuem certa dificuldade em lidar com este tipo de dado, mas eu sei também que existem certas "manhas matemáticas" que possibilitam realizar tais contas sem a necessidade de ponto flutuante.

é justamente isto que eu preciso entender.

Exemplo, preciso:

dividir (1/955)

e efetuar o seguinte calculo: ((2*3.14*SQRT(0.228))/(0.953))^2

os numeros sao exemplos mas este calculo precisa ser dinâmico mas a velocidade nao é importante.

alguma luz?

obrigado!
Religion, ideology, resources, land, spite, love or "just because"... No matter how pathetic the reason, it's enough to start a war.
Avatar do usuário
alexcmag
Equipe E-voo.com
Mensagens: 14800
Registrado em: Sex Fev 13, 2004 12:13 pm
Localização: Sao Paulo SP
Contato:

Mensagem por alexcmag »

Putz... saudades das aulas de cálculo numérico...

Bom, a primeira coisa é saber se realmente você precisa tratar os dados como ponto flutuante, ou apenas pode multiplicar por 10, 100, 1000, etc. e trabalhar com outra unidade de medida, ou com frações decimais (ponto fixo).

Se não tiver jeito e no exemplo de dividir um par de números, uma das abordagens é fazer o ponto flutuante "na mão", que é um pouco difícil mas nada do outro mundo.

É pra faculdade?
Avatar do usuário
-=|Novelli|=-
Equipe E-voo.com
Mensagens: 2043
Registrado em: Seg Nov 10, 2003 3:06 pm
Localização: São Paulo SP

Mensagem por -=|Novelli|=- »

Opa alex! como sempre vc dando aquela força!

entao, eu tentei multiplicar por 10, 100, 100, etc, mas acabou que o resultado ficou com mais de 34 casas (limite do tipo integer do arduino) nao sei se estou fazendo alguma coisa errada, ou se realmente é necessário tantas casas p/ escapar do ponto flutuante.

trata-se de um experimento de pendulo simples, onde eu adquiro os intervalos de tempo entre os ciclos, e calculo o periodo.

Após isto eu insiro na formula q passei acima p/ achar g (aceleracao gravitacional). Eu até consegui escapar da raiz quadrada, (pois raiz quadrada elevada ao quadrado dá o proprio numero) mas a divisão nao deu pra escapar nao.

nas simulacoes do excel deu certo, mas no arduino tá dando rolo. eu tenho certeza que pode ser o limite de casas (gera erro no compilador).

Talvez eu precise saber esse esquema de calcular o ponto na mao...
Avatar do usuário
betocastrucci
membro
Mensagens: 2758
Registrado em: Sex Jan 02, 2004 6:19 pm
Localização: Vinhedo SP - 50

Mensagem por betocastrucci »

Novelli,

tente pensar numa solução de tabela (look up table), onde voce pré-calcula os resultados possíveis com uma certa granularidade na entrada. No seu exemplo o tempo deve ser uma variável de finitas possibilidades (tipo 1,2,3...255), ai basta calcular numa planilha o resultado para cada uma destas possibilidades e carregar os resultados num vetor constante. Depois com a medição em tempo real, o próprio valor do tempo será o indice deste vetor. Espero ter sido claro e ajudado.
Avatar do usuário
-=|Novelli|=-
Equipe E-voo.com
Mensagens: 2043
Registrado em: Seg Nov 10, 2003 3:06 pm
Localização: São Paulo SP

Mensagem por -=|Novelli|=- »

Olá beto! obrigado pela dica! eu vou tentar, mas creio que o espaço amostral fique mto grande pois eu divido 2 variaveis por uma terceira ((angulo em radianos*comprimento)/periodo)

au até consigo trabalhar o comprimento e torná-lo inteiro (limitando os comprimentos do pendulo) mas as outras é complicado, é tudo dinamico.


uma possibilidade seria usar um processador de ponto flutuante externo (http://www.sparkfun.com/commerce/product_info.php?products_id=8129) mas seria uma ultima alternativa, pois eu nao acho q esses calculos sao tao dificeis de acertar pro arduino, só falta eu descobrir como ;)

abraçao!
Avatar do usuário
alexcmag
Equipe E-voo.com
Mensagens: 14800
Registrado em: Sex Fev 13, 2004 12:13 pm
Localização: Sao Paulo SP
Contato:

Mensagem por alexcmag »

Ponto flutuante externo acho que é tiro de canhão pra matar mosca neste caso.

Minha sugestão é você fazer seu próprio ponto flutuante, na verdade não é muito difícil, é apenas a aritmética básica que a gente aprendeu no primário mas mudando a base de 10 pra 2.

Tentando desenterrar as aulas de cálculo numérico e os ensinamentos de um colega de trabalho que me explicou aritmética binária há 1110b anos atrás...

No seu exemplo, de dividir 1 por 955, você pode fazer o seguinte:

Decomponha os números em expoente e mantissa, guardando o expoente separado.

Considerando 16 bits de mantissa e 8 de expoente (com offset de 128, ou seja, expoente de 128=0), sem sinal pra facilitar, dá para fazer assim:

Numeral 1:
E=10000000b
M=0000000000000001b

Numeral 995:
E=10000000b
M=0000001111100011b

Lembra daqueles truques de mudar a posição da vírgula no dividendo e tirar os zeros à direita do divisor para dividir mais facilmente? Tipo 1,123 / 2,00 , a gente faz 1123 / 2 e depois coloca a vírgula de volta ?

Pois bem, ajuste o dividendo diminuindo o expoente e aumentando a mantissa até que o bit mais significativo esteja preenchido, você pode fazer isto rotacionando a mantissa para a esquerda enquanto decrementa o expoente.

Em C de microcontrolador seria algo tipo "while (!m.15) { e--; m<<=1; }":

E=10000000b
M=0000000000000001b

E=01111111b
M=0000000000000010b

E=01111110b
M=0000000000000100b

E=01111101b
M=0000000000001000b

E=01111100b
M=0000000000010000b

E=01111011b
M=0000000000100000b

E=01111010b
M=0000000001000000b

E=01111001b
M=0000000010000000b

E=01111000b
M=0000000100000000b

E=01110111b
M=0000001000000000b

E=01110110b
M=0000010000000000b

E=01110101b
M=0000100000000000b

E=01110100b
M=0001000000000000b

E=01110011b
M=0010000000000000b

E=01110010b
M=0100000000000000b

E=01110001b
M=1000000000000000b

Faça com o divisor, no sentido contrário, rotacionando para a direita e incrementando o expoente até que o bit menos significativo seja 1. No caso do 995, já serve como está. Em C de microcontrolador seria algo tipo "while (!m.0) { e++; m>>=1; }":

Agora você tem um numerozão (32768) para dividir por um numero pequeno (995), que dá 32 e resto 928. Se o resto for maior que a metade do divisor, some um no quociente, caso contrário deixe como está (arredondamento). Fica então 33.

Aí é só subtrair o expoente do divisor do expoente do dividendo. No caso, 113-128=-15, como estamos trabalhando com um offset de 128, se precisarmos deste número para outra operação soma-se 128 a ele e fica-se com 113 novamente.

O resultado da divisão acima então fica sendo
100001b * 2^-15

Para transformando isto para ponto fixo, basta deslocar o ponto decimal 15 pra esquerda, então fica:

100001b * 2^-15
=00000000000000000000100001.0b * 2^-15
=00000000000.000000000100001b

que dá 1/1024+1/32768 = 0,00103759765625d (se não errei nenhuma conta)

Fazendo em decimal na calculadora deu 0,0010050251256281407035175879396985 , um erro relativamente pequeno para esta brincadeira, considerando-se que a mantissa foi de 16 bits.

Se você usar expoente de 32 bits fica mais preciso, claro.

Existem bibliotecas de ponto flutuante, mas se você precisa somente de divisão e multiplicação, tá fácil.
Responder