Ignorante no urtimo...

Software e Hardware para ATMEL

Moderadores: 51, guest2003, brasilma

Ignorante no urtimo...

Mensagempor brasilma » 04 Set 2008 22:22

Amigos,

Estou adorando o C, as rotininhas que estou desenvolvendo estão show de bola, porem preciso de ajuda para me situar e não fazer coisas muito erradas, e que depois tenha de fazer muitas alterações.

No projetinho que estou fazendo irei trabalhar com números com até 7 digitos +/- 9.999.999 e provavelmente terei de utilizar variáveis do tamanho de uma long.

Porem estes números possuem ponto decimal (ex: 123.456, 123.4567).

Quais são as opções para trabalhar com isso em C???

Float?
" A Teoria orienta e a Prática decide" ;-)
Avatar do usuário
brasilma
Dword
 
Mensagens: 3621
Registrado em: 11 Out 2006 15:39
Localização: Planeta Terra

Mensagempor rubenprom » 04 Set 2008 23:42

Eu acho, que terias de trabalhar co numeros inteiros, e depois tratar estes numeros. Tipo seja dividindpo por 10 ou 100 ou por 1000 e mostrar a unidade, a dezena e a centena..e assim vai...
rubenprom
Byte
 
Mensagens: 222
Registrado em: 16 Out 2006 00:23
Localização: Porto Alegre - RS

Mensagempor Maurício » 04 Set 2008 23:48

Fala, brasilma.

Tem várias técnicas, mas, como eu sempre vou pela mais fácil, FLOAT é o melhor caminho. Se não forem muito cálculos, o AVR se sai muito bem. Tou usando aqui pra temperatura e umidade, e até agora o cara não gritou, eheheheheheh

[]'s
"Não leve a vida tão à sério, afinal, nenhum de nós sairá vivo, dela!"
Avatar do usuário
Maurício
Word
 
Mensagens: 678
Registrado em: 14 Out 2006 17:23
Localização: São Paulo - SP

Mensagempor msamsoniuk » 05 Set 2008 00:28

depende do tamanho do numero e da precisao da fracao que vc precisa!

uma solucao seria usar a tecnica de ponto fixo, muito usada em DSPs.

por exemplo, vc poderia definir os numeros como long, usando os primeiros 24 bits para a parte inteira e os ultimos 8 bits para a parte fracionaria. o numero PI, por exemplo, ficaria:

PI = INT(3.141492*256) = 804

o intervalo ficaria com algo tipo: +/- 8388607 na parte inteira e entre 0.0039 (1/256) e 0.996 (255/256) na parte fracionaria. um pouco abaixo da sua necessidade de 7 digitos... mas vamos lah!

na hora de somar e subtrair, vc simplesmente faria as operacoes diretamente, por exemplo, PI+PI seria algo como 804+804=1608. que dividido por 256 eh justamente o valor 6.28125.

na hora de multiplicar a coisa complica um pouco, por dois motivos:

- a multiplicacao de dois operandos de tamanho m e n gera um operando de tamanho m+n. por exemplo, multiplicar dois numeros de 14 bits gera um numero de 28 bits.

- a multiplicacao de dois operandos com ponto nos bits p e q gera um operando com ponto no bit p+q. por exemplo, multiplicar dois numeros com fracoes de 8 bits gera um numero com fracao de 16 bits.

assim, na pratica, PI*PI seria algo como 804*804=646416. o resultado parece bastante grande, em especial pq o ponto fixo esta no lugar errado! se fizermos um pequeno ajuste, obtemos o valor correto: (804*804)>>8 = 2525, onde 2525 dividido por 256 eh precisamente 9.863, o valor procurado.

por outro lado, nao eh possivel usar numeros relativamente grandes entre si.

outra solucao seria usar float, mas ele tambem tem 32 bits de tamanho, o que muda eh o arranjo interno: 24 bits de mantissa e 8 bits de expoente, o que permite escrever numeros tipo +/- 8388607 x 2^+/-127. a vantagem da notacao exponencial eh que vc pode facilmente escrever numeros muito grandes ou muito pequenos, mas surpresa, a parte "inteira" um pouco abaixo da sua necessidade de 7 digitos, tal como na notacao de ponto fixo.

assim, se vc precisa de algo realmente cavalar, a solucao que sobra eh usar double, que permite expoentes cavalares de 53 bits sinalizados e expoentes de 11 bits, permitindo expressar numeros cavalares tipo +/-450359962737kkkk x 2^+/-1023 (o kkkk eh a parte q nem minha calculadora nao conseguiu mostrar hahaha).

obviamente a vantagem de usar float e double eh a comodidade, eh tudo transparente. as vezes, porem, a performance extra eh um requisito forte e acaba compensando usar ponto fixo, especialmente em DSPs e FPGA, onde todo ganho de performance sempre eh bem-vindo.
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor brasilma » 05 Set 2008 08:56

Nos programas em assembler trabalho somente com inteiros e como conheço o roteiro de cálculos vou controlando a posição do ponto decimal nos resultados.

A limitação disto é que o sistema fica fixo.

Agora com C e depois das explicações dos colegas, já estou imaginando qual caminho seguir, vou configurar todo o sistema para a resolução máxima, e quando as entradas apresentarem uma resolução menor que sobrem zeros no final.

Afinal de contas zero a direita da parte significativa da fração não representa nada.

Mais uma vez muito agradecido a todos, vocês não imaginam como estas trocas de ideia ajudam.
" A Teoria orienta e a Prática decide" ;-)
Avatar do usuário
brasilma
Dword
 
Mensagens: 3621
Registrado em: 11 Out 2006 15:39
Localização: Planeta Terra

Mensagempor Maurício » 05 Set 2008 19:14

Pois, é.

Mas, se vc escrever os mesmos códigos que vc escreve em ASM, pra C, vc garante a portabilidade do programa. O que é simplesmente, ótimo! 8)

O caso é que já EXISTE uma variável na linguagem pra tratar ponto flutuante. Se existe, porque não usar? 8)

Funciona!

E depois, pra exibir, já existem OUTRAS funções prontas, que convertem seu número pra qualquer outro tipo do C. Daí pra imprimir... hehehehehe

[]'s
"Não leve a vida tão à sério, afinal, nenhum de nós sairá vivo, dela!"
Avatar do usuário
Maurício
Word
 
Mensagens: 678
Registrado em: 14 Out 2006 17:23
Localização: São Paulo - SP

Mensagempor Djalma Toledo Rodrigues » 06 Set 2008 13:34

As vezes C >>> Asm. (O Prog Objeto sempre é maior)
O mais chato do C é " _"


:D
Editado pela última vez por Djalma Toledo Rodrigues em 17 Dez 2009 23:49, em um total de 1 vez.
Avatar do usuário
Djalma Toledo Rodrigues
Dword
 
Mensagens: 2334
Registrado em: 03 Ago 2008 13:22

Mensagempor brasilma » 08 Set 2008 20:46

Boa Noite Amigos,

No sisteminha que estou desenvolvendo, estou tentando utilizar apenas comandos básicos em C para criar todas as funções que necessito, isto é importante.

Tenho tentado pensar bastante sobre tudo que estou fazendo, para como comentei, não ter de refazer muitas coisas até o final do projeto - não ter de mudar nada, creio que seja impossivel.

Para solucionar o problema de calculos e exibição dos valores, analisei as idéias passadas e pensei no seguinte: realizar todos os cálculos complexos utilizados variáveis long (32bits) e criar uma rotina de exibição em que envio a variável a ser exibida e a posição para o pto decimal, ela converte o número em ascii e comanda a rotina print para exibir tudo certinho, o que acham?

Abraços.
" A Teoria orienta e a Prática decide" ;-)
Avatar do usuário
brasilma
Dword
 
Mensagens: 3621
Registrado em: 11 Out 2006 15:39
Localização: Planeta Terra

Mensagempor styg » 09 Set 2008 13:36

Pegando o bonde andando, mas..

C quer passar a variavel e a posição do ponto decimal, mas pra saber onde vai o ponto decimal c vai ter q faze uns testes certo?
Entao mais vale c passar só a variavel como parametro pra essa função, e definir onde fica o ponto decimal dentro dela, isso evita que vc tenha q calcular a posição do ponto cada vez que for chamar essa funcao, e economiza flash.

c eh q eu entendi direito.. hehe
Lucas
Avatar do usuário
styg
Word
 
Mensagens: 799
Registrado em: 16 Out 2006 08:24
Localização: Floripa abaixo de zero.

Mensagempor msamsoniuk » 09 Set 2008 15:04

ueh, mas se eh "ponto fixo", eh pq o decimal vai estar sempre no mesmo lugar...nao eh ? (:

um exemplo bem simples e tosco:

int pi = 3141; // pi*1000;
printf("pi = %d.%d\n",pi/1000,pi%1000);

armazena a variavel como inteiro e permite fazer todos calculos como inteiro, mas na hora de imprimir eh bem facil colocar o ponto no lugar certo e imprime corretamente 3.141.

isso eh similar ao armazenamento de hora e data na forma de segundos:

long timestamp = 86399; // 23*3600+59*60+59

printf("hora = %d:%d:%d\n",timestamp/3600,(timestamp/60)%60,timestamp%60);

vai imprimir corretamente 23:59:59, com a vantagem que vc soma ou subtrai valores em segundos diretamente sem se preocupar com nada.
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor brasilma » 09 Set 2008 16:11

Fala aê Sty, tudo belezuca?

A idéia é utilizar esta rotina de impressão de valores 32bits de forma genérica, ou seja, todos os valores que precisarem ser impressos no programa, com ou sem pontos e em qualquer lugar, a utilizarão.

Capici?

Abraços.
" A Teoria orienta e a Prática decide" ;-)
Avatar do usuário
brasilma
Dword
 
Mensagens: 3621
Registrado em: 11 Out 2006 15:39
Localização: Planeta Terra

Mensagempor brasilma » 09 Set 2008 17:13

Boa Jogada Marcelo,

Estou gostando desses macetes, me fale se usa bastante este tipo de recurso em seus programas ou se está apenas me dando exemplos.

Infelizmente não uso a rotina printf padrão, meu display é um GLCD e a rotina print foi eu que escrevi, por isso tenho de fazer essas outras de suporte.

Ok?

Abraços.
" A Teoria orienta e a Prática decide" ;-)
Avatar do usuário
brasilma
Dword
 
Mensagens: 3621
Registrado em: 11 Out 2006 15:39
Localização: Planeta Terra

Mensagempor msamsoniuk » 09 Set 2008 21:17

depende da plataforma!

exceto pelo PC mesmo, acho que nao tem nenhum processador sequer q eu trabalhe que tem fpu integrada, entao eu costumo nao usar ponto flutuante.

no caso dos DSPs, eh comum o uso de coeficientes reais que variam de 0 a 1. nesse caso eu uso ponto fixo direto, multiplicando por algum numero 2^n. depois de multiplicar pelos dados, apenas faco shift n, algo como:

Código: Selecionar todos
y[i] += (k[i]*x[i])>>8;


supondo que o coeficiente k[i] foi previamente multiplicado por 256. isso eh um termo de um filtro qq em um DSP, onde y[] sao as saidas, k[] os coeficientes e x[] as entradas. como normalmente se trabalha com poucas entradas, o negocio eh meio realtime e tem que ser rapidao para rodar cada termo do filtro.

mas os DSPs tem multiplicacao bem veloz, pior eh nos 68xxx e HC908. dae eu tento usar artificios para evitar multiplicacao e divisao de inteiros mesmo, pq fica comprometendo a performance. no 68000 um div demora 144 clocks!

por exemplo, no lugar de incrementar um timestamp numa interrupcao de um segundo e depois quebrar com mod e div para imprimir:

Código: Selecionar todos
int timestamp=0;

interrupt timer()
{
    timestamp++;
}

printf("%d:%d:%d\n",timestamp/3600,(timestamp/60)%60,timestamp%60);


poderia ser mais interessante fazer:

Código: Selecionar todos
char h=0,m=0,s=0;

interrupt timer()
{
    s++;
    if(s==60)
    {
        s=0;
        m++;
        if(m==60)
        {
            m=0;
            h++
        }
    }
}

printf("%d:%d:%d\n",h,m,s);


com isso evita-se varios div e mod o tempo todo. mesmo num coldfire rapido jah tive que lutar para econimizar uns clocks, pq mesmo sendo rapido, precisava trabalhar em realtime e nao podia ficar muito tempo parado nas interrupcoes.

vc pode analisar isso e aplicar em todo lugar, questao de verificar:

a) onde posso usar ponto fixo no lugar de ponto flutuante
b) onde quebrar em mais variaveis eh vantagem
c) onde posso arredondar para 2^n
d) onde posso trocar mul e div por shift
e) onde posso trocar mod por and

e por ae vai...o lado ruim disso tudo eh q obfusca o codigo, fica dificil das pessoas entenderem o que vc quer fazer hehehe

ah! eu tb nao uso printf padrao, uso a printf que eu mesmo fiz, dae consome menos memoria! hehehe
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor Djalma Toledo Rodrigues » 09 Set 2008 22:00

:idea: Existe um DSP Texas com ponto flutuante.
Editado pela última vez por Djalma Toledo Rodrigues em 17 Dez 2009 23:50, em um total de 1 vez.
Avatar do usuário
Djalma Toledo Rodrigues
Dword
 
Mensagens: 2334
Registrado em: 03 Ago 2008 13:22

Mensagempor brasilma » 09 Set 2008 22:28

Marcelo, com certeza assim que surgir uma oportunidade irei utilizar estas idéias.

Para que usa DSP?

Abraços.
" A Teoria orienta e a Prática decide" ;-)
Avatar do usuário
brasilma
Dword
 
Mensagens: 3621
Registrado em: 11 Out 2006 15:39
Localização: Planeta Terra

Próximo

Voltar para AVR

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

cron

x