Come si arrotonda un numero in virgola mobile in Perl?
-
05-07-2019 - |
Domanda
Come posso arrotondare un numero decimale (virgola mobile) al numero intero più vicino?
per es.
1.2 = 1
1.7 = 2
Soluzione
Output di perldoc -q round
Perl ha una funzione round ()? Che dire di ceil () e floor ()? Funzioni Trig?Ricorda che
int ()
si riduce semplicemente verso0
. Per arrotondare a un determinato numero di cifre,sprintf ()
oprintf ()
è generalmente il più semplice itinerario.
printf("%.3f", 3.1415926535); # prints 3.142
Il modulo
POSIX
(parte della distribuzione standard Perl) implementaceil ()
,floor ()
e una serie di altri aspetti matematici e trigonometrici funzioni.
use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
In 5.000 a 5.003 perls, la trigonometria è stata eseguita nel
Math :: Complex
modulo. Con 5.004, il moduloMath :: Trig
(parte di lo standard Perl distribuzione) implementa le funzioni trigonometriche. Internamente utilizza ilMath :: Complex
e alcune funzioni possono non funzionare fuori dal asse reale nel piano complesso, ad esempio il seno inverso di 2.L'arrotondamento delle applicazioni finanziarie può avere serie implicazioni e il metodo di arrotondamento utilizzato deve essere specificato con precisione. In questi casi, probabilmente paga non fidarsi di qualsiasi arrotondamento del sistema usato da Perl, ma per implementare invece la funzione di arrotondamento è necessario te stesso.
Per capire il motivo, nota come avrai ancora un problema a metà strada alternanza:
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
Non dare la colpa a Perl. È lo stesso di C. IEEE dice che dobbiamo fare Questo. Numeri Perl i cui valori assoluti sono numeri interi in
2 ** 31
(attivo Macchine a 32 bit) funzionerà praticamente come numeri interi matematici. Altri numeri non sono garantiti.
Altri suggerimenti
Pur non essendo in disaccordo con le complesse risposte sui marchi a metà strada e così via, per il caso d'uso più comune (e forse banale):
my $ arrotondato = int ($ float + 0,5);
Aggiorna
Se è possibile che il tuo $ float
sia negativo, la seguente variazione produrrà il risultato corretto:
my $ arrotondato = int ($ float + $ float / abs ($ float * 2 || 1));
Con questo calcolo -1,4 viene arrotondato a -1 e da -1,6 a -2 e lo zero non esploderà.
Puoi utilizzare un modulo come Math :: Round :
use Math::Round;
my $rounded = round( $float );
O puoi farlo nel modo rozzo:
my $rounded = sprintf "%.0f", $float;
Se decidi di usare printf o sprintf, tieni presente che usano Arrotonda la metà al metodo pari .
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
Vedi perldoc / perlfaq :
Ricorda che
int ()
si limita a troncare verso 0. Per arrotondare a certo numero di cifre,sprintf ()
oprintf ()
è di solito il percorso più semplice.printf("%.3f",3.1415926535); # prints 3.142
Il modulo
POSIX
(parte della distribuzione standard Perl) implementaceil ()
,floor ()
e una serie di altri aspetti matematici e funzioni trigonometriche.use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
In 5.000 a 5.003 perl, la trigonometria è stata eseguita nel modulo
Math :: Complex
.Con 5.004, il modulo
Math :: Trig
(parte della distribuzione standard Perl) > implementa le funzioni trigonometriche.Internamente utilizza il modulo
Math :: Complex
e alcune funzioni possono non funzionare fuori dall'asse reale nel piano complesso, ad esempio il seno inverso di 2.L'arrotondamento nelle applicazioni finanziarie può avere serie implicazioni e l'arrotondamento il metodo utilizzato deve essere specificato con precisione. In questi casi, probabilmente paga non farlo fidati di qualsiasi arrotondamento di sistema sia utilizzato da Perl, ma invece di implementare il funzione di arrotondamento che ti serve.
Per capire perché, nota come avrai ancora un problema con l'alternanza a metà percorso:
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
Non dare la colpa a Perl. È lo stesso di C. IEEE dice che dobbiamo fare Questo. Numeri Perl i cui valori assoluti sono numeri interi inferiori a 2 ** 31 (attivo Macchine a 32 bit) funzionerà praticamente come numeri interi matematici. Altri numeri non sono garantiti.
Non è necessario alcun modulo esterno.
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print Non è necessario alcun modulo esterno.
<*>
Forse mi manca il punto, ma ho pensato che fosse un modo molto più pulito di fare lo stesso lavoro.
Ciò che fa è scorrere tutti i numeri positivi nell'elemento, stampare il numero e il numero intero arrotondato nel formato menzionato. Il codice concatena il rispettivo intero positivo arrotondato solo in base ai decimali. int ($ _) sostanzialmente arrotondamento per difetto il numero, quindi ($ -int ($ )) acquisisce i decimali. Se i decimali sono (per definizione) strettamente inferiori a 0,5, arrotondare per eccesso il numero. In caso contrario, arrotondare per eccesso aggiungendo 1.
.' = '.( ( ( Non è necessario alcun modulo esterno.
<*>
Forse mi manca il punto, ma ho pensato che fosse un modo molto più pulito di fare lo stesso lavoro.
Ciò che fa è scorrere tutti i numeri positivi nell'elemento, stampare il numero e il numero intero arrotondato nel formato menzionato. Il codice concatena il rispettivo intero positivo arrotondato solo in base ai decimali. int ($ _) sostanzialmente arrotondamento per difetto il numero, quindi ($ -int ($ )) acquisisce i decimali. Se i decimali sono (per definizione) strettamente inferiori a 0,5, arrotondare per eccesso il numero. In caso contrario, arrotondare per eccesso aggiungendo 1.
-int( Non è necessario alcun modulo esterno.
<*>
Forse mi manca il punto, ma ho pensato che fosse un modo molto più pulito di fare lo stesso lavoro.
Ciò che fa è scorrere tutti i numeri positivi nell'elemento, stampare il numero e il numero intero arrotondato nel formato menzionato. Il codice concatena il rispettivo intero positivo arrotondato solo in base ai decimali. int ($ _) sostanzialmente arrotondamento per difetto il numero, quindi ($ -int ($ )) acquisisce i decimali. Se i decimali sono (per definizione) strettamente inferiori a 0,5, arrotondare per eccesso il numero. In caso contrario, arrotondare per eccesso aggiungendo 1.
))<0.5) ? int( Non è necessario alcun modulo esterno.
<*>
Forse mi manca il punto, ma ho pensato che fosse un modo molto più pulito di fare lo stesso lavoro.
Ciò che fa è scorrere tutti i numeri positivi nell'elemento, stampare il numero e il numero intero arrotondato nel formato menzionato. Il codice concatena il rispettivo intero positivo arrotondato solo in base ai decimali. int ($ _) sostanzialmente arrotondamento per difetto il numero, quindi ($ -int ($ )) acquisisce i decimali. Se i decimali sono (per definizione) strettamente inferiori a 0,5, arrotondare per eccesso il numero. In caso contrario, arrotondare per eccesso aggiungendo 1.
) : int( Non è necessario alcun modulo esterno.
<*>
Forse mi manca il punto, ma ho pensato che fosse un modo molto più pulito di fare lo stesso lavoro.
Ciò che fa è scorrere tutti i numeri positivi nell'elemento, stampare il numero e il numero intero arrotondato nel formato menzionato. Il codice concatena il rispettivo intero positivo arrotondato solo in base ai decimali. int ($ _) sostanzialmente arrotondamento per difetto il numero, quindi ($ -int ($ )) acquisisce i decimali. Se i decimali sono (per definizione) strettamente inferiori a 0,5, arrotondare per eccesso il numero. In caso contrario, arrotondare per eccesso aggiungendo 1.
)+1 );
print "\n";
}
Forse mi manca il punto, ma ho pensato che fosse un modo molto più pulito di fare lo stesso lavoro.
Ciò che fa è scorrere tutti i numeri positivi nell'elemento, stampare il numero e il numero intero arrotondato nel formato menzionato. Il codice concatena il rispettivo intero positivo arrotondato solo in base ai decimali. int ($ _) sostanzialmente arrotondamento per difetto il numero, quindi ($ -int ($ )) acquisisce i decimali. Se i decimali sono (per definizione) strettamente inferiori a 0,5, arrotondare per eccesso il numero. In caso contrario, arrotondare per eccesso aggiungendo 1.
Quanto segue arrotonderà i numeri positivi o negativi a una determinata posizione decimale:
sub round ()
{
my ($x, $pow10) = @_;
my $a = 10 ** $pow10;
return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a);
}
Di seguito è riportato un esempio di cinque diversi modi per sommare i valori. Il primo è un modo ingenuo per eseguire la somma (e non riesce). Il secondo tenta di utilizzare sprintf ()
, ma anche questo fallisce. Il terzo usa sprintf ()
mentre gli ultimi due (4 ° e 5 °) usano 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
Nota che floor ($ value + 0,5)
può essere sostituito con int ($ value + 0.5)
per rimuovere la dipendenza da POSIX
.
I numeri negativi possono aggiungere alcune stranezze di cui le persone devono essere a conoscenza.
Gli approcci in stile printf
ci forniscono numeri corretti, ma possono comportare delle visualizzazioni dispari. Abbiamo scoperto che questo metodo (a mio avviso, stupidamente) inserisce un segno -
se dovrebbe o non dovrebbe o meno. Ad esempio, -0,01 arrotondato al primo decimale restituisce un -0,0, anziché solo 0. Se hai intenzione di seguire l'approccio di stile printf
e sai che non vuoi un decimale, usa % d
e non % f
(quando hai bisogno di decimali, è quando il display diventa traballante).
Mentre è corretto e per la matematica non è un grosso problema, per la visualizzazione sembra strano mostrare qualcosa come " -0.0 " ;.
Per il metodo int, i numeri negativi possono cambiare ciò che si desidera di conseguenza (anche se ci sono alcuni argomenti che possono essere fatti, sono corretti).
Il int + 0.5
causa problemi reali con numeri negativi, a meno che tu non voglia che funzioni in questo modo, ma immagino che la maggior parte delle persone non lo faccia. -0.9 probabilmente dovrebbe arrotondare a -1, non a 0. Se sai che vuoi che il negativo sia un soffitto piuttosto che un pavimento, puoi farlo in una riga, altrimenti potresti voler usare il metodo int con un minore modifica (questo ovviamente funziona solo per recuperare numeri interi:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
La mia soluzione per 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 );
Se ti preoccupi solo di ottenere un valore intero da un numero intero in virgola mobile (ovvero 12347.9999 o 54321.0001), questo approccio (preso in prestito e modificato dall'alto) farà il trucco:
my $rounded = floor($float + 0.1);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'