¿Cómo redondeas un número de punto flotante en Perl?
-
05-07-2019 - |
Pregunta
¿Cómo puedo redondear un número decimal (punto flotante) al entero más cercano?
por ejemplo
1.2 = 1
1.7 = 2
Solución
Salida de perldoc -q round
¿Tiene Perl una función round ()? ¿Qué pasa con ceil () y floor ()? Funciones de disparo?Recuerde que
int ()
simplemente trunca hacia0
. Para redondear a un cierto número de dígitos,sprintf ()
oprintf ()
suele ser la más fácil ruta.
printf("%.3f", 3.1415926535); # prints 3.142
El módulo
POSIX
(parte de la distribución estándar de Perl) implementaceil ()
,floor ()
, y una serie de otras funciones matemáticas y trigonométricas funciones
use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
En 5.000 a 5.003 perls, la trigonometría se realizó en
Math :: Complex
módulo. Con 5.004, el móduloMath :: Trig
(parte de el perl estandar distribución) implementa las funciones trigonométricas. Internamente utiliza el móduloMath :: Complex
y algunas funciones pueden fallar fuera de la Eje real en el plano complejo, por ejemplo, el seno inverso de 2.El redondeo en aplicaciones financieras puede tener serias implicaciones, y El método de redondeo utilizado debe especificarse con precisión. En estos En algunos casos, probablemente vale la pena no confiar en el redondeo del sistema. utilizado por Perl, pero para implementar la función de redondeo que necesita tú mismo.
Para ver por qué, observe cómo seguirá teniendo un problema en el punto medio alternancia:
for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i} 0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 0.8 0.8 0.9 0.9 1.0 1.0
No culpes a Perl. Es lo mismo que en C. IEEE dice que tenemos que hacer esta. Los números de Perl cuyos valores absolutos son enteros en
2 ** 31
(en Máquinas de 32 bits) funcionarán de manera muy similar a los enteros matemáticos Otros números no están garantizados.
Otros consejos
Aunque no esté en desacuerdo con las complejas respuestas sobre las marcas a mitad de camino, etc., para el caso de uso más común (y posiblemente trivial):
my $ rounded = int ($ float + 0.5);
ACTUALIZAR
Si es posible que su $ float
sea negativo, la siguiente variación producirá el resultado correcto:
my $ rounded = int ($ float + $ float / abs ($ float * 2 || 1));
Con este cálculo, -1.4 se redondea a -1, y -1.6 a -2, y el cero no explotará.
Puedes usar un módulo como Math :: Round :
use Math::Round;
my $rounded = round( $float );
O puedes hacerlo de manera cruda:
my $rounded = sprintf "%.0f", $float;
Si decides usar printf o sprintf, ten en cuenta que usan Redondear la mitad para igualar método.
foreach my $i ( 0.5, 1.5, 2.5, 3.5 ) {
printf "$i -> %.0f\n", $i;
}
__END__
0.5 -> 0
1.5 -> 2
2.5 -> 2
3.5 -> 4
Consulte perldoc / perlfaq :
Recuerde que
int ()
simplemente trunca hacia 0. Para redondear a un Cierto número de dígitos,sprintf ()
oprintf ()
suele ser el Ruta más fácil.printf("%.3f",3.1415926535); # prints 3.142
El módulo
POSIX
(parte de la distribución Perl estándar) implementaceil ()
,floor ()
, y una serie de otros y funciones trigonométricas.use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
En 5.000 a 5.003 perls, la trigonometría se realizó en el módulo
Math :: Complex
.Con 5.004, el módulo
Math :: Trig
(parte de la distribución Perl estándar) > implementa las funciones trigonométricas.Internamente utiliza el módulo
Math :: Complex
y algunas funciones pueden interrumpirse desde el eje real al plano complejo, por ejemplo, el seno inverso de 2.El redondeo en las aplicaciones financieras puede tener serias implicaciones, y el redondeo El método utilizado debe especificarse con precisión. En estos casos, probablemente vale la pena no confíe en cualquier redondeo del sistema que esté utilizando Perl, pero para implementar el Función de redondeo que necesita usted mismo.
Para ver por qué, observe cómo seguirá teniendo un problema en la alternancia de medio punto:
for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i } 0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 0.8 0.8 0.9 0.9 1.0 1.0
No culpes a Perl. Es lo mismo que en C. IEEE dice que tenemos que hacer esta. Los números de Perl cuyos valores absolutos son enteros menores de 2 ** 31 (en Máquinas de 32 bits) funcionarán de manera muy similar a los enteros matemáticos Otros números no están garantizados.
No necesitas ningún módulo externo.
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print No necesitas ningún módulo externo.
<*>
Puede que me esté perdiendo tu punto, pero pensé que esta era una forma mucho más limpia de hacer el mismo trabajo.
Lo que esto hace es recorrer cada número positivo en el elemento, imprimir el número y el entero redondeado en el formato que mencionaste. El código concatena el entero positivo redondeado respectivo solo en función de los decimales. int ($ _) básicamente redondea hacia abajo el número, de modo que ($ -int ($ )) captura los decimales. Si los decimales son (por definición) estrictamente menores a 0.5, redondea el número hacia abajo. Si no, redondea agregando 1.
.' = '.( ( ( No necesitas ningún módulo externo.
<*>
Puede que me esté perdiendo tu punto, pero pensé que esta era una forma mucho más limpia de hacer el mismo trabajo.
Lo que esto hace es recorrer cada número positivo en el elemento, imprimir el número y el entero redondeado en el formato que mencionaste. El código concatena el entero positivo redondeado respectivo solo en función de los decimales. int ($ _) básicamente redondea hacia abajo el número, de modo que ($ -int ($ )) captura los decimales. Si los decimales son (por definición) estrictamente menores a 0.5, redondea el número hacia abajo. Si no, redondea agregando 1.
-int( No necesitas ningún módulo externo.
<*>
Puede que me esté perdiendo tu punto, pero pensé que esta era una forma mucho más limpia de hacer el mismo trabajo.
Lo que esto hace es recorrer cada número positivo en el elemento, imprimir el número y el entero redondeado en el formato que mencionaste. El código concatena el entero positivo redondeado respectivo solo en función de los decimales. int ($ _) básicamente redondea hacia abajo el número, de modo que ($ -int ($ )) captura los decimales. Si los decimales son (por definición) estrictamente menores a 0.5, redondea el número hacia abajo. Si no, redondea agregando 1.
))<0.5) ? int( No necesitas ningún módulo externo.
<*>
Puede que me esté perdiendo tu punto, pero pensé que esta era una forma mucho más limpia de hacer el mismo trabajo.
Lo que esto hace es recorrer cada número positivo en el elemento, imprimir el número y el entero redondeado en el formato que mencionaste. El código concatena el entero positivo redondeado respectivo solo en función de los decimales. int ($ _) básicamente redondea hacia abajo el número, de modo que ($ -int ($ )) captura los decimales. Si los decimales son (por definición) estrictamente menores a 0.5, redondea el número hacia abajo. Si no, redondea agregando 1.
) : int( No necesitas ningún módulo externo.
<*>
Puede que me esté perdiendo tu punto, pero pensé que esta era una forma mucho más limpia de hacer el mismo trabajo.
Lo que esto hace es recorrer cada número positivo en el elemento, imprimir el número y el entero redondeado en el formato que mencionaste. El código concatena el entero positivo redondeado respectivo solo en función de los decimales. int ($ _) básicamente redondea hacia abajo el número, de modo que ($ -int ($ )) captura los decimales. Si los decimales son (por definición) estrictamente menores a 0.5, redondea el número hacia abajo. Si no, redondea agregando 1.
)+1 );
print "\n";
}
Puede que me esté perdiendo tu punto, pero pensé que esta era una forma mucho más limpia de hacer el mismo trabajo.
Lo que esto hace es recorrer cada número positivo en el elemento, imprimir el número y el entero redondeado en el formato que mencionaste. El código concatena el entero positivo redondeado respectivo solo en función de los decimales. int ($ _) básicamente redondea hacia abajo el número, de modo que ($ -int ($ )) captura los decimales. Si los decimales son (por definición) estrictamente menores a 0.5, redondea el número hacia abajo. Si no, redondea agregando 1.
Lo siguiente redondeará los números positivos o negativos a una posición decimal dada:
sub round ()
{
my ($x, $pow10) = @_;
my $a = 10 ** $pow10;
return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a);
}
A continuación se muestra una muestra de cinco formas diferentes de sumar valores. La primera es una forma ingenua de realizar la suma (y falla). El segundo intenta usar sprintf ()
, pero también falla. El tercero usa sprintf ()
con éxito, mientras que los dos últimos (4th y amp; 5th) usan floor ($ value + 0.5)
.
use strict;
use warnings;
use POSIX;
my @values = (26.67,62.51,62.51,62.51,68.82,79.39,79.39);
my $total1 = 0.00;
my $total2 = 0;
my $total3 = 0;
my $total4 = 0.00;
my $total5 = 0;
my $value1;
my $value2;
my $value3;
my $value4;
my $value5;
foreach $value1 (@values)
{
$value2 = $value1;
$value3 = $value1;
$value4 = $value1;
$value5 = $value1;
$total1 += $value1;
$total2 += sprintf('%d', $value2 * 100);
$value3 = sprintf('%1.2f', $value3);
$value3 =~ s/\.//;
$total3 += $value3;
$total4 += $value4;
$total5 += floor(($value5 * 100.0) + 0.5);
}
$total1 *= 100;
$total4 = floor(($total4 * 100.0) + 0.5);
print '$total1: '.sprintf('%011d', $total1)."\n";
print '$total2: '.sprintf('%011d', $total2)."\n";
print '$total3: '.sprintf('%011d', $total3)."\n";
print '$total4: '.sprintf('%011d', $total4)."\n";
print '$total5: '.sprintf('%011d', $total5)."\n";
exit(0);
#$total1: 00000044179
#$total2: 00000044179
#$total3: 00000044180
#$total4: 00000044180
#$total5: 00000044180
Tenga en cuenta que floor ($ value + 0.5)
se puede reemplazar con int ($ value + 0.5)
para eliminar la dependencia en POSIX
.
Los números negativos pueden agregar algunas peculiaridades que las personas deben tener en cuenta.
Los enfoques de estilo printf
nos dan números correctos, pero pueden dar como resultado algunas visualizaciones impares. Hemos descubierto que este método (en mi opinión, estúpidamente) coloca en un signo -
si debería o no debería o no. Por ejemplo, -0.01 redondeado a un lugar decimal devuelve un -0.0, en lugar de solo 0. Si va a hacer el enfoque de estilo printf
, y sabe que no quiere un decimal, use % d
y no % f
(cuando necesitas decimales, es cuando la pantalla se pone borrosa).
Si bien es correcto y para las matemáticas no es gran cosa, para mostrarlo solo se ve raro mostrando algo como " -0.0 " ;.
Para el método int, los números negativos pueden cambiar lo que quieres como resultado (aunque hay algunos argumentos que pueden ser correctos).
El int + 0.5
causa problemas reales con los números negativos, a menos que quieras que funcione de esa manera, pero imagino que la mayoría de las personas no lo hacen. -0.9 probablemente debería redondear a -1, no a 0. Si sabe que quiere que el negativo sea un techo en lugar de un piso, entonces puede hacerlo en una sola línea, de lo contrario, puede usar el método int con un menor modificación (esto obviamente solo funciona para recuperar números enteros:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
Mi solución para sprintf
if ($value =~ m/\d\..*5$/){
$format =~ /.*(\d)f$/;
if (defined $1){
my $coef = "0." . "0" x $1 . "05";
$value = $value + $coef;
}
}
$value = sprintf( "$format", $value );
Si solo le interesa obtener un valor entero de un número de punto flotante completo (es decir, 12347.9999 o 54321.0001), este enfoque (tomado en préstamo y modificado desde arriba) hará el truco:
my $rounded = floor($float + 0.1);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'