Função atof()

1. Função atof()

Felipe da Silva Morais
FelipeSmithCS

(usa Outra)

Enviado em 16/03/2017 - 22:02h

Eae pessoal, estava fazendo um algoritmo pra ler os dados de um arquivo separado por vírgula, passar esses dados para uma matriz do tipo float para poder realizar contas com os dados do arquivo. Então usei a função fgets pra pegar cada linha e percorre-la de virgula em virgula, salvando os valores em uma variável (char) e depois convertendo essa variável para uma outra variável tipo float, mas a função atof() está modificando alguns valores na hora da conversão. Exemplo:

Se o char vale -999.99, na hora de printar o valor já convertido aparece -999.989990. Alguma ideia do porque?
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<locale.h>
#include<string.h>
float** alocamatriz(float **m, int l, int c){
int cont;
m=(float**)malloc(sizeof(float*)*l);
for(cont=0;cont<l;cont++){
m[cont]=(float*)malloc(sizeof(float)*c);
}
return m;
}
int main(){
FILE *arq,*arquivo;
char vetor[5000],*valor,*valor2,vetor2[5000];
float **m,ventomedio,soma=0,aux=-999.989990,vento,v,z;
int l=0,c=0,cont,linha=0,coluna;
//Leitura do coeficiente
printf("Digite o valor de z:");
scanf("%f",&z);
//Abertura do arquivo
arq = fopen("Dados.txt","rt");
if(arq==NULL){
printf("Erro na abertura do arquivo!\n");
exit(0);
}
//Verificação do arquivo para saber o numero de linhas e colunas(Necessario na alocação da matriz)
while (fgets(vetor, sizeof(vetor), arq)){
valor = strtok(vetor,",");
while (valor != NULL){
valor = strtok(NULL, ",");
if(l==0){
c++;
}
}
l++;
}
//Alocação da matriz
m=alocamatriz(m,l,c);
fclose(arq);
//Reabertura do arquivo
arq = fopen("Dados.txt","rt");
if(arq==NULL){
printf("Erro na abertura do arquivo!\n");
exit(0);
}
//Passagem dos dados do arquivo para a matriz
while (fgets(vetor2, sizeof(vetor2), arq)){
valor2=strtok(vetor2, ",");
if(linha!=0){
m[linha][0]=atof(valor2);
}
coluna=1;
while (valor2 != NULL){
valor2 = strtok(NULL, ",");
if(linha!=0){
m[linha][coluna]=atof(valor2); //Revisar essa função
}
coluna++;
}
linha++;
}

// Calculo do vento medio, raiz(u^2+v^2)
for(linha=1;linha<l;linha++){
if(m[linha][8]!=aux && m[linha][9]!=aux){
vento=sqrt(pow(m[linha][8],2)+pow(m[linha][9],2)); // raiz de u^2+v^2
soma=soma+vento;
}
}
//Vento medio na altura de 3 metros
ventomedio=soma/(l-1);
//Cria o arquivo onde sera salvo o resultado
arquivo=fopen("Resultado.txt","wt");
//Simulações
for(cont=10;cont<=100;cont=cont+10){
v=ventomedio*(log(3/z)/log(cont/z));
fprintf(arquivo,"Vento medio a Altura de %dm: %f\n ",cont,v);
}
//Fecha os arquivos
fclose(arq);
fclose(arquivo);
system("pause");
return 0;
}



  


2. Re: Função atof()

Uilian Ries
uilianries

(usa Linux Mint)

Enviado em 17/03/2017 - 00:35h

Você pode imprimir a precisão desejada:

#include<stdio.h>
int main(){
printf("%.2f\n", -999.99F);
}


Irá imprimir precisamente -999.99

Também prefira utilizar strtod do que atof. A função possui validação de erro.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h>

int main(){
char string [256] = {0};
char* end;
errno = 0;
scanf("%s", string);
const double result = strtod(string, &end);

if ((result == DBL_MIN || result == DBL_MAX) && errno != 0) {
perror("Valor fora do limite");
} else if (end == string) {
perror("Erro durante a conversão");
} else if (result > DBL_MAX) {
perror("acima do limite superior");
} else if (result < DBL_MIN) {
perror("abaixo do limite inferior");
} else if ('\0' != *end) {
perror("Caracter extra na entrada");
} else {
printf("%.2f\n", result);
}
}



3. Re: Função atof()

Paulo
paulo1205

(usa Ubuntu)

Enviado em 17/03/2017 - 19:33h

Possivelmente é problema de precisão, induzido por causa de um sistema de numeração diferente do que você espera.

Lembra da notação científica para números, em que você expressaria um valor qualquer por meio de uma mantissa pertencente ao intervalo [1,10[ dos números reais, multiplicada por uma potência de dez? Por exemplo: 123.456.789 é expresso como 1,23456789·10^9; 0,00625 é expresso como 6,25·10^(-3).

Pois então, números de ponto flutuante no PC funcionam da mesma maneira, mas são expressos como números racionais (não mais reais) no intervalo [1,2[ e com uma quantidade limitada de bits de precisão (24 bits no caso de float e 53 bits para double, de modo que o bit menos significativo vale, respectivamente, 2^(-23) ou 2^(-52) vezes menos do que o bit da parte inteira), e o multiplicador é uma potência de dois, não uma potência de dez.

O problema de arredondamento acontece porque os números que vêm à direita da vírgula correspondem a frações cujos denominadores são expressos como potências dos respectivos sistemas de numeração, e essas frações, num caso geral, nem sempre podem ser representadas exatamente no outro sistema de numeração.

Tomemos, como exemplo, o valor decimal 1,1. Para convertê-lo em binário, podemos fazer o seguinte: isolar a parte inteira e convertê-la, e depois converter a parte fracionária. Neste caso, a parte inteira é 1, cuja conversão para binário é trivial, valendo exatamente 1. Já a parte fracionária corresponde à fração 1/10, que nós teremos de representar como uma fração ou uma soma de frações cujos denominadores são potências inteiras de 2. Quais seriam as frações candidatas? 1/2 não serve, porque é maior do que 1/10. 1/4 e 1/8 também não, pelo mesmo motivo. A próxima é 1/16 (cujo valor decimal é 0,0625), então podemos assumir que 0,1 pode ser composto por 1/16 mais algumas outras frações ainda menores, cuja soma seja igual a 0,0375 (1-0,0625). 1/32 pode entrar nessa composição, pois vale 0,03125, produzindo um novo resíduo de 0,00625 (0,0375-0,03125). 1/64 (0,015625) e 1/128 (0,0078125) ficam fora, pois são maiores que o resíduo, mas 1/256 e 1/512 entram.

Se você prosseguir com essa conversão, vai notar o surgimento de uma dízima periódica binária, na forma 0,0001100110011001100110011... (na base 2!), sem jamais zerar o resíduo daquele singelo e tão bem comportado 0,1 decimal.

Toda dízima é infinta, mas o seu computador tem um número finito de bits para armazená-la, e isso implica que o seu número terá de ser truncado (ou arredondado) na hora que acabarem os bits.

Somado a isso, há um outro problema. A parte inteira também ocupa espaço no número. Num caso simples como 1,1, essa parte inteira ocupa apenas um bit, logo deixando 23 (float) ou 52 (double) bits livres para representar a parte facionária. No entanto, se você tiver um número cuja parte inteira seja 999, que precisa de 10 bits para ser representado, esses nove bits a mais serão tirados da parte disponível para representar a fração. Então aqueles 23 bits disponíveis originalmente para representar a fração num float viram apenas 14. Se você fizer as contas (simples, por sinal: multiplicando 14 por log10(2), que dá pouco mais do que 4,2), você verá que 14 bits não permitem representar com precisão nada após a quarta casa decimal. E do que estaria antes, até essa quarta casa, ainda existe o problema do possível resíduo inexato.

Nossos PCs usam representação de ponto flutuante baseada no padrão IEEE-754 de 1985. Procure ler a respeito do assunto.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts