collapse

* Posts Recentes

Alguém arranja motores? por almamater
[11 de Dezembro de 2024, 16:07]


Sistema a LASER que será também capaz de matar moscas por jm_araujo
[11 de Dezembro de 2024, 12:35]


Nevadent - Não carrega por almamater
[22 de Novembro de 2024, 21:36]


Classmate Leap T304 não liga por almamater
[19 de Novembro de 2024, 07:13]


+ LASERs por dropes
[18 de Novembro de 2024, 21:50]


Dúvida com fonte de alimentação comutada por filjoa
[28 de Outubro de 2024, 21:57]


Motoserra Stihl 120C por dropes
[26 de Outubro de 2024, 19:01]


Shelly em jeito de watchdog por SerraCabo
[24 de Outubro de 2024, 19:24]


Meu novo robô por josecarlos
[06 de Outubro de 2024, 13:33]


Sirene NOVA maluca por dropes
[01 de Outubro de 2024, 18:26]

Autor Tópico: conversão char  (Lida 4139 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline dio123

  • Mini Robot
  • *
  • Mensagens: 1.034
conversão char
« em: 08 de Novembro de 2020, 19:26 »
Boa noite,
tenho uma mensagem defenida com char[120] com 4 informações separadas por espaços.
Acontece que na mensagem tenho os seguintes valores 1234 0.2 5.0 03
consigo separar por 4 variáveis char usando um contador de espaços e memcopy.

Agora a minha duvida é tenho
Citar
float set_distance =0.00;
set_distance = atof(copy);

No copy o valor é 0.2
Onde dá o resultado 0.200000003

Outro exemplo copy =5.1
Onde dá o resultado 5.0999999999999996


« Última modificação: 08 de Novembro de 2020, 19:36 por dio123 »

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.980
  • NERD!
Re: conversão char
« Responder #1 em: 08 de Novembro de 2020, 22:07 »
É mesmo assim, tem que ver com a forma com os números são codificados em float.
Tudo que trabalha com floats tem esse "problema",  mesmo calculadoras, o truque é fazer como elas, e não usar mais dígitos significativos do que a precisão da variável, e o arredondamento trata do resto.
« Última modificação: 08 de Novembro de 2020, 22:10 por jm_araujo »

Offline KammutierSpule

  • Mini Robot
  • *
  • Mensagens: 1.494
Re: conversão char
« Responder #2 em: 09 de Novembro de 2020, 11:52 »
Se estiveres num sistema com constrangimentos de recursos (microcontrolador) sugiro que nao uses floats.
Tens de converter os numeros para outro formato (eg fixed point)
ou se mesmo quiseres usar floats, na conversao para char* usa uma funcao tua que converta primeiro o numero para inteiro.

em ultimo caso, recomendo usar a funcao sscanf e aí poderas controlar o formato, exemplo, %.1f irá colocar no maximo 1 casa decimal.

Offline dio123

  • Mini Robot
  • *
  • Mensagens: 1.034
Re: conversão char
« Responder #3 em: 09 de Novembro de 2020, 12:43 »
Neste momento só de cabeça tenho umas 8 variáveis em float, que na pratica não cria uma coisa tão arrojada, basta um tipo de variável que permita guardar um valores com 2 casas decimais.

Até porque a ideia vai ser gravar esses valores numa eeprom por ser valores de configuração do meu programa, que vai  ler a eeprom externa cada vez que o stm32 arranca.
« Última modificação: 09 de Novembro de 2020, 12:53 por dio123 »

Offline blabla

  • Mini Robot
  • *
  • Mensagens: 258
Re: conversão char
« Responder #4 em: 12 de Novembro de 2020, 09:56 »
Bom dia,
Sugiro que continue a usar floating point para os cálculos pois é mais simples do que fixed point, isto desde que não existam constrangimentos de espaço da lib, ou de necessidades de performance.
Se mesmo assim necessitar de fixed point eu coloquei 3 links interessantes que explicam fixed point nesta página de github:

How to learn modern Embedded Systems
https://github.com/joaocarvalhoopen/How_to_learn_modern_Embedded_Systems

O código em baixo exemplifica como poderá fazer o arredondamento para 2 casas decimais.

Código: [Seleccione]
// Online C compiler to run C program online
// https://www.programiz.com/c-programming/online-compiler/
#include <stdio.h>
#include <math.h>
#include <string.h>

void fillRoundStr(char *outBuf, float num) {
    int roundNum = round(num*100);
    sprintf(outBuf, "%d.%d%d", roundNum/100, (roundNum / 10) % 10, roundNum % 10);
}

int main() {
    float a = 0.0;
    float b = 0.0;
    float c = 0.0;
    float d = 0.0;
   
    // Ler da string que vem da EEPROM.
    char inputBuf[120] = "1234 0.22001 5.00506 0.30004";
    printf("InputBuf:%s\n", inputBuf);
    sscanf(inputBuf, "%f %f %f %f", &a, &b, &c, &d);
   
    // Para escrever para o ecrã.
    char strTmpA[10];
    char strTmpB[10];
    char strTmpC[10];
    char strTmpD[10];
    fillRoundStr(strTmpA, a);
    printf("round of  %f is  %s\n", a, strTmpA);
    fillRoundStr(strTmpB, b);
    printf("round of  %f is  %s\n", b, strTmpB);
    fillRoundStr(strTmpC, c);
    printf("round of  %f is  %s\n", c, strTmpC);
    fillRoundStr(strTmpD, d);
    printf("round of  %f is  %s\n", d, strTmpD);
   
    // Para escrever novamente para uma string fazer.
    char outputBuf[120];
    sprintf(outputBuf, "%s %s %s %s", strTmpA, strTmpB, strTmpC, strTmpD);
   
    printf("outputBuf:%s", outputBuf);
   
    return 0;
}



Resultado:
Código: [Seleccione]
InputBuf:1234 0.22001 5.00506 0.30004
round of  1234.000000 is  1234.00
round of  0.220010 is  0.22
round of  5.005060 is  5.01
round of  0.300040 is  0.30
outputBuf:1234.00 0.22 5.01 0.30

Cumprimentos,
João Carvalho

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.980
  • NERD!
Re: conversão char
« Responder #5 em: 12 de Novembro de 2020, 10:29 »
Qual é o problema de fazeres antes:
Código: [Seleccione]
void fillRoundStr(char *outBuf, float num) {
    sprintf(outBuf, "%.2f", num);
}
(mantenho a função fillRoundStr para manter a estrutura do restante código)


A menos que saibas que problema estás a resolver (o autor do tópico não referiu limitações de tamanho, arquitetura nem velocidade), o teu código replica uma funcionalidade existente, com necessidade extras de memória (variáveis e stack), aumento de complexidade para quem ler o código,  e com os compiladores de hoje em dia pode até "atrapalhar" nas otimizações na hora da compilação

Um senhor muito mais inteligente do que eu disse: "Premature optimization is the root of all evil" (atribuida a Donald Knuth, o "mestre" dos algoritmos). Não quer dizer que não se otimize código, mas é preciso saber com que objetivo se faz, e sempre que possível que seja mesurável.

Longe vai o tempo de transformar os ciclos "for" em "do...while" decrescentes para o compilador cuspir um "dec A/ jnz LOOP" e poupar um par de words de memória.
« Última modificação: 12 de Novembro de 2020, 10:36 por jm_araujo »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: conversão char
« Responder #6 em: 12 de Novembro de 2020, 10:36 »
Meh, fartei-me de usar floats em AVR e nunca tive problema nenhum com isso, e o mesmo com sprintf, para quê andar com chanatos, leva um sprintf que usava tipo 1.5K de flash e siga, a diferença de preço de um atmega8 para um 328p é irrisória para uso pessoal, para uso comercial um avr não faz sentido com ARMs a 20-30 centimos com mais flash, ram e IO..
Avr fanboy

Offline blabla

  • Mini Robot
  • *
  • Mensagens: 258
Re: conversão char
« Responder #7 em: 12 de Novembro de 2020, 11:39 »
Bom dia,

Na realidade jm_araujo tem toda a razão, obrigado por chamar-me à atenção.
O especificador de precisão em C na formatação faz arredondamento normal  e eu pensava que fazia somente corte nas duas casas decimais.

Isto pode ser visto por exemplo em
“The Precision field usually specifies a maximum limit on the output, depending on the particular formatting type. For floating point numeric types, it specifies the number of digits to the right of the decimal point that the output should be rounded.

https://en.wikipedia.org/wiki/Printf_format_string

Result:

Código: [Seleccione]
void fillRoundStr(char *outBuf, float num) {
    int roundNum = round(num*100);
    sprintf(outBuf, "%d.%d%d", roundNum/100, (roundNum / 10) % 10, roundNum % 10);
}

void fillRoundStr_2(char *outBuf, float num) {
    sprintf(outBuf, "%.2f", num);
}

InputBuf:1234 0.22001 5.00506 0.30004
round of  1234.000000 is  1234.00
round_2 of  1234.000000 is  1234.00
round of  0.220010 is  0.22
round_2 of  0.220010 is  0.22
round of  5.005060 is  5.01
round_2 of  5.005060 is  5.01
round of  0.300040 is  0.30
round_2 of  0.300040 is  0.30
outputBuf:1234.00 0.22 5.01 0.30

Cumprimentos,
João Carvalho

Offline KammutierSpule

  • Mini Robot
  • *
  • Mensagens: 1.494
Re: conversão char
« Responder #8 em: 12 de Novembro de 2020, 16:25 »
o teu código replica uma funcionalidade existente, com necessidade extras de memória (variáveis e stack)

+-
Em geral os ARM compilados com GCC e as bibliotecas std que costumam disponibilizar, nao tem por defeito a funcionalidade de floats nos printf e tem de ser activada essa opcao no IDE. Quando e' activada a opcao,  aumenta a quantidade de memoria usada por essa funcionalidade.

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.980
  • NERD!
Re: conversão char
« Responder #9 em: 12 de Novembro de 2020, 17:45 »
Correto, era apenas uma lista de desvantagens do código complexo, e sem saber quais as necessidades de espaço e se já é usado o printf de floats pelo autor original, é otimização prematura "complicar" o a função.

Offline blabla

  • Mini Robot
  • *
  • Mensagens: 258
Re: conversão char
« Responder #10 em: 12 de Novembro de 2020, 20:10 »
Gostaria de deixar só uma nota.
Aquilo que parece ser muito óbvio, nomeadamente como é feito o arredondamento, no passado já teve muitas inconsistências como podem ver no link seguinte:

Inconsistent Rounding of Printed Floating-Point Numbers
https://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/

Seja como for, de cabeça pensava que era por arredondamento por corte e não arredondamento tradicional.

Cumprimentos,
João Carvalho

Offline dio123

  • Mini Robot
  • *
  • Mensagens: 1.034
Re: conversão char
« Responder #11 em: 14 de Novembro de 2020, 15:35 »
Boa tarde,
Não preciso de nada complexo a refazer um gps tracker, no entanto foi aproveitar uma app android que já uso a muito tempo, e a instalação.
A questão é que há alguns campos como a distancia, distancia de alerta, voltagem de alerta bateria, distancia entre coordenadas, em que app envia por sms para o hardware e estão com uma casa decimal.
Depois é usar esses valores para comparação em if's.
Dai ter a noção que ter muitos floats e calculos pode causar impacto no desempenho. Pelo menos quanto tentei fazer num atmega328 foi o que aconteceu.
Quando alarme disparava ler as coordenadas, calcular distancia das coordenadas iniciais e actuais, ver se esta na distancia do perímetro segurança, enviar sms, voltar a ler. Se fizesse uma chamada para o alarme para desarmar  maioria das vezes nao conseguia.




Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: conversão char
« Responder #12 em: 15 de Novembro de 2020, 18:04 »
Isso não é nada de pesado para um AVR, tens é código bloqueante, altera a coisa para funcionar em "paralelo".
Avr fanboy