Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 04-04-2012
briast briast is offline
Miembro
NULL
 
Registrado: may 2011
Posts: 50
Poder: 14
briast Va por buen camino
Problema con redondeos en doubles

Hola. Tengo un problema con los redondeos cuando la variable es de tipo double. Cuando es extended va bien. El problema se reproduce tanto en Delphi 5 como en Delphi 2010, haciendo la misma prueba en ambos.
No sé de donde viene el problema, pero me gustaría determinar si lo mejor es usar siempre extended. Este problema se agudiza cuando tienes dos doubles y comparas, diciéndote que son diferentes cuando en realidad deberían ser iguales.
Os pongo el código fuente para que lo veáis:

a) Ejemplo de rendondeo por pantalla en un bucle. Tengo en pantalla un botón y dos campos memo.
Código:
procedure TForm1.Button1Click(Sender: TObject);
var pp,pp2:Double;
    kk,kk2:Extended;
    j:smallint;
begin
    { case RadioGroup1.ItemIndex of
     0:Math.SetRoundMode(rmNearest);
     1:Math.SetRoundMode(rmUp);
     2:Math.SetRoundMode(rmDown);
     3:Math.SetRoundMode(rmTruncate);
     end;   }

     memo1.Lines.Clear;
     memo2.lines.clear;
     pp:=0.005;
     kk:=0.005;

     pp2:=-0.005;
     kk2:=-0.005;

     for j := 1 to 100 do
       begin
           pp:=pp+0.01;
           kk:=kk+0.01;
           pp2:=pp2-0.01;
           kk2:=kk2-0.01;

           if formatfloat('0.00',pp)=formatfloat('0.00',kk) then
             memo1.Lines.Add(floattostr(pp)+' | '+formatfloat('0.00',pp)+' | '+formatfloat('0.00',kk)+' | '+floattostr(kk))
           else memo1.Lines.Add(floattostr(pp)+' | '+formatfloat('0.00',pp)+' | '+formatfloat('0.00',kk)+' | '+floattostr(kk)+' <--- error');

           if formatfloat('0.00',pp2)=formatfloat('0.00',kk2) then
             memo2.Lines.Add(floattostr(pp2)+' | '+formatfloat('0.00',pp2)+' | '+formatfloat('0.00',kk2)+' | '+floattostr(kk2))
           else memo2.Lines.Add(floattostr(pp2)+' | '+formatfloat('0.00',pp2)+' | '+formatfloat('0.00',kk2)+' | '+floattostr(kk2)+' <--- error');

       end;
end;
El texto entre comentarios para el radiogroup es para cambiar el método de redondeo en delphi 2010 (unit math), pero el resultado es el mismo (excepto con rmDown). La cuestión es que si se ejecuta sale algo como lo siguiente:
Código:
MEMO1:
0,015 | 0,01 | 0,02 | 0,015 <--- error
0,025 | 0,02 | 0,03 | 0,025 <--- error
0,035 | 0,03 | 0,04 | 0,035 <--- error
0,045 | 0,04 | 0,05 | 0,045 <--- error
0,055 | 0,06 | 0,06 | 0,055
0,065 | 0,07 | 0,07 | 0,065
0,075 | 0,07 | 0,08 | 0,075 <--- error
0,085 | 0,08 | 0,09 | 0,085 <--- error
0,095 | 0,09 | 0,10 | 0,095 <--- error
0,105 | 0,10 | 0,11 | 0,105 <--- error
0,115 | 0,11 | 0,12 | 0,115 <--- error
0,125 | 0,12 | 0,13 | 0,125 <--- error
0,135 | 0,13 | 0,14 | 0,135 <--- error
0,145 | 0,14 | 0,15 | 0,145 <--- error
0,155 | 0,15 | 0,16 | 0,155 <--- error
0,165 | 0,17 | 0,17 | 0,165
0,175 | 0,18 | 0,18 | 0,175
0,185 | 0,19 | 0,19 | 0,185
0,195 | 0,20 | 0,20 | 0,195
0,205 | 0,21 | 0,21 | 0,205
0,215 | 0,22 | 0,22 | 0,215
0,225 | 0,23 | 0,23 | 0,225
0,235 | 0,24 | 0,24 | 0,235
0,245 | 0,25 | 0,25 | 0,245
0,255 | 0,26 | 0,26 | 0,255
0,265 | 0,27 | 0,27 | 0,265
0,275 | 0,28 | 0,28 | 0,275
0,285 | 0,29 | 0,29 | 0,285
0,295 | 0,30 | 0,30 | 0,295
0,305 | 0,31 | 0,31 | 0,305
0,315 | 0,32 | 0,32 | 0,315
0,325 | 0,33 | 0,33 | 0,325
0,335 | 0,34 | 0,34 | 0,335
0,345 | 0,35 | 0,35 | 0,345
0,355 | 0,36 | 0,36 | 0,355
0,365 | 0,37 | 0,37 | 0,365
0,375 | 0,38 | 0,38 | 0,375
0,385 | 0,39 | 0,39 | 0,385
0,395 | 0,40 | 0,40 | 0,395
0,405 | 0,41 | 0,41 | 0,405
0,415 | 0,42 | 0,42 | 0,415
0,425 | 0,43 | 0,43 | 0,425
0,435 | 0,44 | 0,44 | 0,435
0,445 | 0,45 | 0,45 | 0,445
0,455 | 0,46 | 0,46 | 0,455
0,465 | 0,47 | 0,47 | 0,465
0,475 | 0,48 | 0,48 | 0,475
0,485 | 0,49 | 0,49 | 0,485
0,495 | 0,50 | 0,50 | 0,495
0,505 | 0,51 | 0,51 | 0,505
0,515 | 0,52 | 0,52 | 0,515
0,525 | 0,53 | 0,53 | 0,525
0,535 | 0,54 | 0,54 | 0,535
0,545 | 0,55 | 0,55 | 0,545
0,555 | 0,56 | 0,56 | 0,555
0,565 | 0,57 | 0,57 | 0,565
0,575 | 0,58 | 0,58 | 0,575
0,585 | 0,59 | 0,59 | 0,585
0,595 | 0,60 | 0,60 | 0,595
0,605 | 0,61 | 0,61 | 0,605
0,615 | 0,62 | 0,62 | 0,615
0,625 | 0,63 | 0,63 | 0,625
0,635 | 0,64 | 0,64 | 0,635
0,645 | 0,65 | 0,65 | 0,645
0,655 | 0,66 | 0,66 | 0,655
0,665 | 0,67 | 0,67 | 0,665
0,675 | 0,68 | 0,68 | 0,675
0,685 | 0,69 | 0,69 | 0,685
0,695 | 0,70 | 0,70 | 0,695
0,705 | 0,71 | 0,71 | 0,705
0,715 | 0,72 | 0,72 | 0,715
0,725 | 0,73 | 0,73 | 0,725
0,735 | 0,74 | 0,74 | 0,735
0,745 | 0,75 | 0,75 | 0,745
0,755 | 0,76 | 0,76 | 0,755
0,765 | 0,77 | 0,77 | 0,765
0,775 | 0,78 | 0,78 | 0,775
0,785 | 0,79 | 0,79 | 0,785
0,795 | 0,80 | 0,80 | 0,795
0,805 | 0,81 | 0,81 | 0,805
0,815000000000001 | 0,82 | 0,82 | 0,815
0,825000000000001 | 0,83 | 0,83 | 0,825
0,835000000000001 | 0,84 | 0,84 | 0,835
0,845000000000001 | 0,85 | 0,85 | 0,845
0,855000000000001 | 0,86 | 0,86 | 0,855
0,865000000000001 | 0,87 | 0,87 | 0,865
0,875000000000001 | 0,88 | 0,88 | 0,875
0,885000000000001 | 0,89 | 0,89 | 0,885
0,895000000000001 | 0,90 | 0,90 | 0,895
0,905000000000001 | 0,91 | 0,91 | 0,905
0,915000000000001 | 0,92 | 0,92 | 0,915
0,925000000000001 | 0,93 | 0,92 | 0,925 <--- error
0,935000000000001 | 0,94 | 0,93 | 0,935 <--- error
0,945000000000001 | 0,95 | 0,94 | 0,945 <--- error
0,955000000000001 | 0,96 | 0,95 | 0,955 <--- error
0,965000000000001 | 0,97 | 0,96 | 0,965 <--- error
0,975000000000001 | 0,98 | 0,97 | 0,975 <--- error
0,985000000000001 | 0,99 | 0,98 | 0,985 <--- error
0,995000000000001 | 1,00 | 0,99 | 0,995 <--- error
1,005 | 1,01 | 1,01 | 1,005
Como véis hay diferencias entre redondear a dos decimales un double y un extended. Pero lo más extraño de todo es que 0,805 + 0,01 da 0,8150000000001. Aquí empieza otro problema. En el memo2 tenemos:
Código:
MEMO2:
-0,015 | -0,01 | -0,02 | -0,015 <--- error
-0,025 | -0,02 | -0,03 | -0,025 <--- error
-0,035 | -0,03 | -0,04 | -0,035 <--- error
-0,045 | -0,04 | -0,05 | -0,045 <--- error
-0,055 | -0,06 | -0,06 | -0,055
-0,065 | -0,07 | -0,07 | -0,065
-0,075 | -0,07 | -0,08 | -0,075 <--- error
-0,085 | -0,08 | -0,09 | -0,085 <--- error
-0,095 | -0,09 | -0,10 | -0,095 <--- error
-0,105 | -0,10 | -0,11 | -0,105 <--- error
-0,115 | -0,11 | -0,12 | -0,115 <--- error
-0,125 | -0,12 | -0,13 | -0,125 <--- error
-0,135 | -0,13 | -0,14 | -0,135 <--- error
-0,145 | -0,14 | -0,15 | -0,145 <--- error
-0,155 | -0,15 | -0,16 | -0,155 <--- error
-0,165 | -0,17 | -0,17 | -0,165
-0,175 | -0,18 | -0,18 | -0,175
-0,185 | -0,19 | -0,19 | -0,185
-0,195 | -0,20 | -0,20 | -0,195
-0,205 | -0,21 | -0,21 | -0,205
-0,215 | -0,22 | -0,22 | -0,215
-0,225 | -0,23 | -0,23 | -0,225
-0,235 | -0,24 | -0,24 | -0,235
-0,245 | -0,25 | -0,25 | -0,245
-0,255 | -0,26 | -0,26 | -0,255
-0,265 | -0,27 | -0,27 | -0,265
-0,275 | -0,28 | -0,28 | -0,275
-0,285 | -0,29 | -0,29 | -0,285
-0,295 | -0,30 | -0,30 | -0,295
-0,305 | -0,31 | -0,31 | -0,305
-0,315 | -0,32 | -0,32 | -0,315
-0,325 | -0,33 | -0,33 | -0,325
-0,335 | -0,34 | -0,34 | -0,335
-0,345 | -0,35 | -0,35 | -0,345
-0,355 | -0,36 | -0,36 | -0,355
-0,365 | -0,37 | -0,37 | -0,365
-0,375 | -0,38 | -0,38 | -0,375
-0,385 | -0,39 | -0,39 | -0,385
-0,395 | -0,40 | -0,40 | -0,395
-0,405 | -0,41 | -0,41 | -0,405
-0,415 | -0,42 | -0,42 | -0,415
-0,425 | -0,43 | -0,43 | -0,425
-0,435 | -0,44 | -0,44 | -0,435
-0,445 | -0,45 | -0,45 | -0,445
-0,455 | -0,46 | -0,46 | -0,455
-0,465 | -0,47 | -0,47 | -0,465
-0,475 | -0,48 | -0,48 | -0,475
-0,485 | -0,49 | -0,49 | -0,485
-0,495 | -0,50 | -0,50 | -0,495
-0,505 | -0,51 | -0,51 | -0,505
-0,515 | -0,52 | -0,52 | -0,515
-0,525 | -0,53 | -0,53 | -0,525
-0,535 | -0,54 | -0,54 | -0,535
-0,545 | -0,55 | -0,55 | -0,545
-0,555 | -0,56 | -0,56 | -0,555
-0,565 | -0,57 | -0,57 | -0,565
-0,575 | -0,58 | -0,58 | -0,575
-0,585 | -0,59 | -0,59 | -0,585
-0,595 | -0,60 | -0,60 | -0,595
-0,605 | -0,61 | -0,61 | -0,605
-0,615 | -0,62 | -0,62 | -0,615
-0,625 | -0,63 | -0,63 | -0,625
-0,635 | -0,64 | -0,64 | -0,635
-0,645 | -0,65 | -0,65 | -0,645
-0,655 | -0,66 | -0,66 | -0,655
-0,665 | -0,67 | -0,67 | -0,665
-0,675 | -0,68 | -0,68 | -0,675
-0,685 | -0,69 | -0,69 | -0,685
-0,695 | -0,70 | -0,70 | -0,695
-0,705 | -0,71 | -0,71 | -0,705
-0,715 | -0,72 | -0,72 | -0,715
-0,725 | -0,73 | -0,73 | -0,725
-0,735 | -0,74 | -0,74 | -0,735
-0,745 | -0,75 | -0,75 | -0,745
-0,755 | -0,76 | -0,76 | -0,755
-0,765 | -0,77 | -0,77 | -0,765
-0,775 | -0,78 | -0,78 | -0,775
-0,785 | -0,79 | -0,79 | -0,785
-0,795 | -0,80 | -0,80 | -0,795
-0,805 | -0,81 | -0,81 | -0,805
-0,815000000000001 | -0,82 | -0,82 | -0,815
-0,825000000000001 | -0,83 | -0,83 | -0,825
-0,835000000000001 | -0,84 | -0,84 | -0,835
-0,845000000000001 | -0,85 | -0,85 | -0,845
-0,855000000000001 | -0,86 | -0,86 | -0,855
-0,865000000000001 | -0,87 | -0,87 | -0,865
-0,875000000000001 | -0,88 | -0,88 | -0,875
-0,885000000000001 | -0,89 | -0,89 | -0,885
-0,895000000000001 | -0,90 | -0,90 | -0,895
-0,905000000000001 | -0,91 | -0,91 | -0,905
-0,915000000000001 | -0,92 | -0,92 | -0,915
-0,925000000000001 | -0,93 | -0,92 | -0,925 <--- error
-0,935000000000001 | -0,94 | -0,93 | -0,935 <--- error
-0,945000000000001 | -0,95 | -0,94 | -0,945 <--- error
-0,955000000000001 | -0,96 | -0,95 | -0,955 <--- error
-0,965000000000001 | -0,97 | -0,96 | -0,965 <--- error
-0,975000000000001 | -0,98 | -0,97 | -0,975 <--- error
-0,985000000000001 | -0,99 | -0,98 | -0,985 <--- error
-0,995000000000001 | -1,00 | -0,99 | -0,995 <--- error
-1,005 | -1,01 | -1,01 | -1,005
Con lo cual pasa lo mismo con los negativos.

Pero ahora, visto lo visto, pongo otro botón en la pantalla y un label y asocio al botón el código siguiente:
Código:
procedure TForm1.Button2Click(Sender: TObject);
var pp,kk:double;
begin
     pp:=0.805;
     kk:=0.815;
     pp:=pp+0.01;
     if pp=kk then label1.caption:='iguales'
     else label1.caption:='distintos: ' + FloatToStr(pp)+ ' <> ' + floattostr(kk);
end;
Si pulsas el botón, en lugar de salir en el label el texto "iguales", aparece el texto: distintos 0,815<>0,815


Algo estoy haciendo mal ... esto no puede ser así ...
Responder Con Cita
  #2  
Antiguo 04-04-2012
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola briast.

Revisá este artículo

Saludos.
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #3  
Antiguo 04-04-2012
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Yo recomendaría la lectura del artículo What Every Computer Scientist Should Know About Floating-Point Arithmetic.
Podrá ser bastante denso y aburrido, sobre todo sabiendo que está en inglés y a algunos no nos fascina ese idioma, pero señala y aborda muchas cuestiones técnicas sobre la aritemética de punto flotante.
Más en puntual sobre la comparación de números de punto flotante el artículo Comparing Floating Point Number aclara muchas cosas. He colocado el enlace a la versión actualizada (a este año).

Ya con eso te puedes hacer una idea de porque es una muy mala idea hacer comparaciones tan directas como lo hacemos de toda la vida con los números enteros

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #4  
Antiguo 05-04-2012
briast briast is offline
Miembro
NULL
 
Registrado: may 2011
Posts: 50
Poder: 14
briast Va por buen camino
Ok. Gracias por la información.
Utilizaré la función para comparar valores disponible en la unit math y ya está.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
sumar valores nulos con doubles sql. ingabraham Varios 5 14-12-2010 23:27:10
Problema con redondeos en campos Money river_1 SQL 3 16-06-2010 01:59:34
Redondeos y no redondeos vivamotos C++ Builder 6 12-06-2010 00:29:48
Redondeos con Firebird 2.0 Jose_T Firebird e Interbase 12 19-01-2007 19:57:02
Problemas con Redondeos AGAG4 Varios 4 14-11-2005 23:38:44


La franja horaria es GMT +2. Ahora son las 02:26:37.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi