• Publicidad

Operaciones con decimales

¿Ya sabes lo que es una referencia? Has progresado, el nível básico es cosa del pasado y ahora estás listo para el siguiente nivel.

Operaciones con decimales

Notapor rafa » 2006-03-08 05:55 @288

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.
rafa
Perlero nuevo
Perlero nuevo
 
Mensajes: 20
Registrado: 2004-05-14 05:04 @252

Publicidad

Notapor monoswim » 2006-03-08 06:54 @329

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
MonoSwim
Perl Programming Language
Avatar de Usuario
monoswim
Perlero nuevo
Perlero nuevo
 
Mensajes: 452
Registrado: 2003-11-18 16:13 @717
Ubicación: Buenos Aires

Re: Operaciones con decimales

Notapor explorer » 2006-03-08 13:52 @619

Este es tu código, que tiene algunas faltas.
Código: Seleccionar todo
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: Seleccionar todo
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.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: CALCULO CON DECIMALES

Notapor Perl user » 2006-03-09 02:21 @139

rafa escribiste: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: Seleccionar todo
@lineas = <FICHERO>;
foreach my $linea (@lineas){
...

Cambiarlo por:
Código: Seleccionar todo
while ( my $line = <FICHERO> ) { # puedes agregar defined() para mayor seguridad
   ...
}


Código: Seleccionar todo
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: Seleccionar todo
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,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

CALCULOS DECIMALES

Notapor rafa » 2006-03-10 08:11 @382

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.
rafa
Perlero nuevo
Perlero nuevo
 
Mensajes: 20
Registrado: 2004-05-14 05:04 @252


Volver a Intermedio

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados

cron