Página 1 de 2
Ignorante no urtimo...

Enviado:
04 Set 2008 22:22
por brasilma
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?

Enviado:
04 Set 2008 23:42
por rubenprom
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...

Enviado:
04 Set 2008 23:48
por Maurício
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

Enviado:
05 Set 2008 00:28
por msamsoniuk
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.

Enviado:
05 Set 2008 08:56
por brasilma
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.

Enviado:
05 Set 2008 19:14
por Maurício
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!
O caso é que já EXISTE uma variável na linguagem pra tratar ponto flutuante. Se existe, porque não usar?
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

Enviado:
06 Set 2008 13:34
por Djalma Toledo Rodrigues
As vezes C >>> Asm. (O Prog Objeto sempre é maior)
O mais chato do C é "
_"


Enviado:
08 Set 2008 20:46
por brasilma
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.

Enviado:
09 Set 2008 13:36
por styg
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

Enviado:
09 Set 2008 15:04
por msamsoniuk
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.

Enviado:
09 Set 2008 16:11
por brasilma
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.

Enviado:
09 Set 2008 17:13
por brasilma
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.

Enviado:
09 Set 2008 21:17
por msamsoniuk
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

Enviado:
09 Set 2008 22:00
por Djalma Toledo Rodrigues

Existe um DSP Texas com ponto flutuante.

Enviado:
09 Set 2008 22:28
por brasilma
Marcelo, com certeza assim que surgir uma oportunidade irei utilizar estas idéias.
Para que usa DSP?
Abraços.