Perl en Español

  1. Home
  2. Tutoriales
  3. Foro
  4. Artículos
  5. Donativos
  6. Publicidad
 

Operaciones con decimales

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Intermedio
Mensaje Mie Mar 08, 2006 4:55 am
rafa
Perlero Nuevo
Perlero Nuevo
Registrado: 14 May 2004
Mensajes: 68
Operaciones con decimales Responder citando

Hola, un saludo a todos.

Tengo una página en perl donde me calcula unas cantidades pero me dan algunos errores en su calculo, ya que si pongo 2 decimales las cantidades no son correctas, no se si sera porque es flotante , la programacion es la siguiente :

open(FICHERO, "$cambio");
my $sumat, $sumat1, $sumat2, $sumat3, $sumat4, $sumat5, $sumat6, $sumat7;
@lineas = <FICHERO>;
foreach my $linea (@lineas){
my @sumana = split(/;/,$linea);
if (@sumana[1] =~ / /){
if (@sumana[3] !~ /TOTAL.COMANDANCIA/){
if (@sumana[3] !~ /TOTAL /){
$sumat = sprintf("%.2f",$sumat + $sumana[4]/$count2);
$sumat1 = sprintf("%.2f",$sumat1 + $sumana[5]/$count2);
$sumat2 = sprintf("%.2f",$sumat2 + $sumana[6]/$count2);
$sumat3 = sprintf("%.2f",$sumat3 + $sumana[8]/$count2);
$sumat4 = sprintf("%.2f",$sumat4 + $sumana[9]/$count2);
$sumat5 = sprintf("%.2f",$sumat5 + $sumana[10]/$count2);
$sumat6 = sprintf("%.2f",$sumat6 + $sumana[11]/$count2);
$sumat7 = sprintf("%.2f",$sumat7 + $sumana[12]/$count2);
}
}
}
}

Por ejemplo la cantida que da en $sumat1 es 6.36, cuando en realidad debe ser 8.20.
las cantidades totales son 24061 y 2932, que divididas dan 8.20.

Si le pongo 4 decimales da la cantidad correcta.
No se que pasa, os agradeciria me dieran una solucion, o que me de solamente números enteros.
Gracias anticipadas.
Mensaje Mie Mar 08, 2006 5:54 am
monoswim
Vive para Perl en Español
Vive para Perl en Español
Registrado: 18 Nov 2003
Mensajes: 716
Ubicación: Buenos Aires
Responder citando

en materia de números prefiero hacer las cuentas con toooodos los decimales y a la hora de imprimirlos hacer una expresión regular para imprimir los primeros 4 dígitos...

Saludos
Mensaje Mie Mar 08, 2006 12:52 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4123
Ubicación: Valladolid, España
Responder citando

Este es tu código, que tiene algunas faltas.
Código:
open(FICHERO, "$cambio");
my $sumat, $sumat1, $sumat2, $sumat3, $sumat4, $sumat5, $sumat6, $sumat7;
@lineas = <FICHERO>;
foreach my $linea (@lineas) {
    my @sumana = split(/;/,$linea);
    if (@sumana[1] =~ / /) {
        if (@sumana[3] !~ /TOTAL.COMANDANCIA/) {
            if (@sumana[3] !~ /TOTAL /) {
                $sumat = sprintf("%.2f",$sumat + $sumana[4]/$count2);
                $sumat1 = sprintf("%.2f",$sumat1 + $sumana[5]/$count2);
                $sumat2 = sprintf("%.2f",$sumat2 + $sumana[6]/$count2);
                $sumat3 = sprintf("%.2f",$sumat3 + $sumana[8]/$count2);
                $sumat4 = sprintf("%.2f",$sumat4 + $sumana[9]/$count2);
                $sumat5 = sprintf("%.2f",$sumat5 + $sumana[10]/$count2);
                $sumat6 = sprintf("%.2f",$sumat6 + $sumana[11]/$count2);
                $sumat7 = sprintf("%.2f",$sumat7 + $sumana[12]/$count2);
            }
        }
    }
}
Esta es otra versión, con algunas cosas cambiadas que luego comento.
Código:
open(FICHERO, "$cambio") or die "ERROR: No pude abrir el fichero $cambio\n";
my $sumat, $sumat1, $sumat2, $sumat3, $sumat4, $sumat5, $sumat6, $sumat7;
my @lineas = <FICHERO>;
close FICHERO;
foreach my $linea (@lineas) {
    my @sumana = split(/;/,$linea);
    if ( $sumana[1] =~ / /) {
        if (@sumana[3] !~ /TOTAL.COMANDANCIA/) {
            $sumat  = $sumat + $sumana[4]/$count2;
            $sumat1 = $sumat1 + $sumana[5]/$count2;
            $sumat2 = $sumat2 + $sumana[6]/$count2;
            $sumat3 = $sumat3 + $sumana[8]/$count2;
            $sumat4 = $sumat4 + $sumana[9]/$count2;
            $sumat5 = $sumat5 + $sumana[10]/$count2;
            $sumat6 = $sumat6 + $sumana[11]/$count2;
            $sumat7 = $sumat7 + $sumana[12]/$count2;
        }
    }
}
printf("%.2f",$sumat);
printf("%.2f",$sumat1);
printf("%.2f",$sumat2);
printf("%.2f",$sumat3);
printf("%.2f",$sumat4);
printf("%.2f",$sumat5);
printf("%.2f",$sumat6);
printf("%.2f",$sumat7);
Esa era la propuesta de monoswim: hacer la suma y luego hacer la presentación con los decimales finales.
Los cambios son:
* Comprobación de que hemos podido abrir el fichero
* Cerramos el fichero con close
* Cambiamos el código @sumana[3] por $sumana[3]
* Quitamos un if por innecesario.

Un detalle importante: recuerda que en el código $sumat = sumat + sumana[4]/$count2, esto es lo mismo que: $sumat = sumat + (sumana[4]/$count2). Como no sabemos el propósito del código, no sabemos si está bien hecho como lo pones o no. Necesitaríamos más pistas... por ejemplo, no sabemos lo que vale $count2.
Mensaje Jue Mar 09, 2006 1:21 am
Perl user
Maestro Honorario
Maestro Honorario
Registrado: 03 Nov 2004
Mensajes: 385
Re: CALCULO CON DECIMALES Responder citando

rafa escribió:
Hola, un saludo a todos.

Tengo una página en perl donde me calcula unas cantidades pero me dan algunos errores en su calculo, ya que si pongo 2 decimales las cantidades no son correctas, no se si sera porque es flotante , la programacion es la siguiente :

open(FICHERO, "$cambio");
my $sumat, $sumat1, $sumat2, $sumat3, $sumat4, $sumat5, $sumat6, $sumat7;
@lineas = <FICHERO>;
foreach my $linea (@lineas){
my @sumana = split(/;/,$linea);
if (@sumana[1] =~ / /){
if (@sumana[3] !~ /TOTAL.COMANDANCIA/){
if (@sumana[3] !~ /TOTAL /){
$sumat = sprintf("%.2f",$sumat + $sumana[4]/$count2);
$sumat1 = sprintf("%.2f",$sumat1 + $sumana[5]/$count2);
$sumat2 = sprintf("%.2f",$sumat2 + $sumana[6]/$count2);
$sumat3 = sprintf("%.2f",$sumat3 + $sumana[8]/$count2);
$sumat4 = sprintf("%.2f",$sumat4 + $sumana[9]/$count2);
$sumat5 = sprintf("%.2f",$sumat5 + $sumana[10]/$count2);
$sumat6 = sprintf("%.2f",$sumat6 + $sumana[11]/$count2);
$sumat7 = sprintf("%.2f",$sumat7 + $sumana[12]/$count2);
}
}
}
}

Por ejemplo la cantida que da en $sumat1 es 6.36, cuando en realidad debe ser 8.20.
las cantidades totales son 24061 y 2932, que divididas dan 8.20.

Si le pongo 4 decimales da la cantidad correcta.
No se que pasa, os agradeciria me dieran una solucion, o que me de solamente números enteros.
Gracias anticipadas.


Que tal,

No obstante las recomendaciones que hace explorer, que son buenas prácticas, recomiendo AMPLIAMENTE hacer una "Refactoración" del código, es decir, hacer un análisis a conciencia para reescribir el código de tal manera que sea mucho mas sencillo de leer y que tenga mucho mejor rendmiento.

En qué parte? Bueno como mencioné, aparte de los comentarios hechos por explorer, podrían haber algunos cambios al respecto:

Código:

@lineas = <FICHERO>;
foreach my $linea (@lineas){
...

Cambiarlo por:
Código:

while ( my $line = <FICHERO> ) { # puedes agregar defined() para mayor seguridad
   ...
}


Código:

if (@sumana[1] =~ / /){
if (@sumana[3] !~ /TOTAL.COMANDANCIA/){
if (@sumana[3] !~ /TOTAL /){
     $sumat  = sprintf("%.2f",$sumat  + $sumana[4]/$count2);
     $sumat1 = sprintf("%.2f",$sumat1 + $sumana[5]/$count2);
     $sumat2 = sprintf("%.2f",$sumat2 + $sumana[6]/$count2);
     $sumat3 = sprintf("%.2f",$sumat3 + $sumana[8]/$count2);
     $sumat4 = sprintf("%.2f",$sumat4 + $sumana[9]/$count2);
     $sumat5 = sprintf("%.2f",$sumat5 + $sumana[10]/$count2);
     $sumat6 = sprintf("%.2f",$sumat6 + $sumana[11]/$count2);
     $sumat7 = sprintf("%.2f",$sumat7 + $sumana[12]/$count2);
}
 }
  }

Estamos de acuerdo que esto es completamente horrible cierto? podemos observar el patrón de una sumatoria en secuencia, es decir, en elementos secuenciales desde 1...7, entonces por qué no utilizar un simple y mortal array?
Y no olvidemos mencionar los horribles 3 if anidados, pudiendolos escribir en una sola sentencia ( con las previas indicaciones hechas nuevamente por explorer ):
Código:

my @sumat;
$#sumatoria = 7; # recortamos el array a solo 7 índices, o sea 8 elementos
....

if ( $sumana[1] =~ / / and
     $sumana[3] !~ /TOTAL.COMANDANCIA/) and
     $sumana[3] !~ /TOTAL /)
{
   my $cont = 4;
   for ( 0..$#sumatoria ) {
      $sumat[$_]  = sprintf( "%.2f", $sumat[$_]  +
                                      $sumana[$cont++] / $count2 );
   }
   #incluso la sentencia anterior puede quedar en una sola línea, pero
   #evitemos la parte "oscura" para mostrar un ejemplo mas claro.
}


Y bueno principalmente eso le daría todo un giro a tu programa... no solo en claridad, sino para mantenerlo.

Ahora bien hay varios puntos que en lo personal no entiendo... uno de ellos es por qué en el if la condición sobre $sumana[3] checa sobre la no existencia del patrón TOTAL y TOTAL.COMANDANCIA? eso en mi punto de vista es un poco ambiguo.

En fin, esas son mis recomendaciones de mi interpretación sobre tu problema.

Best regards,
Mensaje Vie Mar 10, 2006 7:11 am
rafa
Perlero Nuevo
Perlero Nuevo
Registrado: 14 May 2004
Mensajes: 68
CALCULOS DECIMALES Responder citando

En principio quiero daros las gracias a ambos.
De momento lo he hecho como dice Monoswim y ya me da las cantidades correctas, al poner 5 decimales y luego con ...

$uno = $sumat;
$a1 = $uno;
$b1 = substr ($a1, 0, 4);

Respecto a la variable de
$count2 y
if (@sumana[3] !~ /TOTAL.COMANDANCIA/){
if (@sumana[3] !~ /TOTAL /){

es que anteriormente se hace un conteo de la base y se excluye esos registros, porque los mismos son sumas parciales de otros registros que ya hay en la base
De todas formas tomo nota para rectificar la programacion como me dice Explorer.
Un saludo.
Publicar nuevo tema   Responder al tema    Foros de discusión -> Intermedio Todas las horas son GMT - 6 Horas
Página 1 de 1



Powered by phpBB © 2001, 2005 phpBB Group