Problemas de arredondamento double e modf [RESOLVIDO]

1. Problemas de arredondamento double e modf [RESOLVIDO]

ian cléver sales fernandes
ianclever

(usa Arch Linux)

Enviado em 31/03/2014 - 16:33h

Gente é o seguinte estou desenvolvendo uns códigos de hash bem aqui, um é usando método da divisão outro o da multiplicação, fiz até os simuladores para achar qual seria a melhor tabela, estou fazendo usando distribuições do top 100 do distrowatch. Problema é o seguinte no método da multiplicação já estou com o código 99% pronto, o que está me atrapalhando são 3 chaves que estão dando problema no arredondamento, como o código é extenso e tem biblioteca, e ainda lê de um arquivo binário, vou recriar apenas a parte que dá o bug para vcs me ajudarem a solucionar.

a idéia é a seguinte,

k = É a chave;

A= constante onde 0<A<1;

M = é o tamanho da tabela, neste caso uma potência de 2( 16 no caso);

mapear o elemento na tabela consiste em

multiplicar k*A,
retirar a parte fracionária modf(k*A,&partint),

multiplicar isso por M*modf(k*A,&partint),

este resultado será a posição da chave na tabela no caso com o cast para int :(int) M*modf(k*A,&partint);

em código seria:


#include <stdio.h>
#include <stdlib.h>// no caso do codigo pq leio do arquivo
#include <math.h>

#define A 0.41

int main(void)
{
int k1=1201500;
int k2=2463075;
int k3=1261575;
int M=(int)pow(2,4);
double partint;
int posicao;

printf("\n k = %d",k1); // aqui o valor de k está normal
printf("\n A = %.10lf",A)//a tambem está normal 0.41000000
printf("\n k*A = %.10lf",k1*A);/* aqui já está alterado aparece 492614.9999999999 quando deveria aparecer 492615.0000000000*/
printf("\n modf(k*A,&partint) = %,10lf",modf(k1*A,&partint));/*aqui está alterado aparecendo 0.9999999999 quando deveria aparecer 0.0000000000*/
printf("\n M*modf(k*A,&partint) = %.10lf",M*modf(k1*A,&partint));/*aqui está alterado está aparecendo 15.9999999991 quando deveria aparecer 0.0000000000*/
printf("\n (int)M*modf(k*A,&partint) %d",(int)M*modf(k1*A,&partint));/* e aqui aparece 15 onde deveria aparecer 0*/
posicao=(int)M*modf(k1*A,&partint); //internamente é assim os prints são so para ilustrar



printf("\n k = %d",k2); // aqui o valor de k está normal
printf("\n A = %.10lf",A)//a tambem está normal 0.41000000
printf("\n k*A = %.10lf",k2*A);/* aqui já está alterado aparece 1009860.7499999999 quando deveria aparecer 1009860.7500000000*/
printf("\n modf(k*A,&partint) = %,10lf",modf(k2*A,&partint));/*aqui está alterado aparecendo 0.7499999999 quando deveria aparecer 0.7500000000*/
printf("\n M*modf(k*A,&partint) = %.10lf",M*modf(k2*A,&partint));/*aqui está alterado está aparecendo 11.9999999981 quando deveria aparecer 12.0000000000*/
printf("\n (int)M*modf(k*A,&partint) %d",(int)M*modf(k2*A,&partint));/* e aqui aparece 11 onde deveria aparecer 12*/
posicao=(int)M*modf(k2*A,&partint); //internamente é assim os prints são so para ilustrar


printf("\n k = %d",k3); // aqui o valor de k está normal
printf("\n A = %.10lf",A)//a tambem está normal 0.41000000
printf("\n k*A = %.10lf",k3*A);/* aqui já está alterado aparece 517245.7499999999 quando deveria aparecer 517245.7500000000*/
printf("\n modf(k*A,&partint) = %,10lf",modf(k3*A,&partint));/*aqui está alterado aparecendo 0.7499999999 quando deveria aparecer 0.7500000000*/
printf("\n M*modf(k*A,&partint) = %.10lf",M*modf(k3*A,&partint));/*aqui está alterado está aparecendo 11.9999999991 quando deveria aparecer 12.0000000000*/
printf("\n (int)M*modf(k*A,&partint) %d",(int)M*modf(k3*A,&partint));/* e aqui aparece 11 onde deveria aparecer 12*/
posicao=(int)M*modf(k3*A,&partint); //internamente é assim os prints são so para ilustrar
}



como vocês podem perceber eu já estou usando a notação double pq o float não estava suportando corretamente os cálculos, coisa que foi descoberta ainda no simulador, onde era para incrementar de 0.01 em 0.01, ocorria normalmente a te o 0.830000 e aí fazia o arredondamento 839999, coisa que não faz sentido, então optei pelo double com o qual fui feliz com os calculos no simulador(testei inclusive fora a parte em uma calculadora 1 a 1 e os resultados bateram), já no código do hashing, se não fosse por essas benditas 3 chaves estaria tudo bem, mas nem mesmo com long double esse arredondamento estranho some, o que pode ser gente? como solucionar isso?

eu já não sei o que fazer.


  


2. Re: Problemas de arredondamento double e modf [RESOLVIDO]

ian cléver sales fernandes
ianclever

(usa Arch Linux)

Enviado em 01/04/2014 - 12:00h

de acordo com meu próprios testes, descobri o seguinte, por mais que ao printar o double com 100 casas aparecem números até a casa 54 após a vírgula, os números que realmente influem no valor do cálculo são as 15 primeiras casas ,não havendo alteração nos outros numeros independente do valor colocado.

Portanto apesar de que 0.41 em double deveria ser 0.41000000000000000000000000000000000000000000000000...., na realidade ele é 0.40999999999997.... o que com certeza influi e muito no cálculo, devido a isso apesar de em uma notação científica isso estar errado para o meu caso o que resolveu foi enganar o double da seguinte maneira:

A=0.410000000000001;

note "15" casas após a vírgula

deste modo como os valores suportáveis pelo double não vão até a 16ª casa ele entende isso como:

0.4100000000000097 que não é 0.410000000000000000000000000000000000000000000000000000... mas também não influi nos meus cáculos, e corrige o erro. Afinal se para double 0.410000000000000000000000000000000000000.... pode ser 0.409999999999997....(que também é errado), que mal há em eu usar a notação errada.

Vou fechar o tópico, se alguém tiver alguma informação mais detalhada a respeito, por favor fique a vontade para expor, pois eu também estou a fim de entender isso de forma correta.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts