Pergunta

Como posso arredondar um número decimal (ponto flutuante) para o número inteiro mais próximo?

por exemplo.

1.2 = 1
1.7 = 2
Foi útil?

Solução

Saída de perldoc -q round

Será que Perl tem uma função round ()? E sobre ceil () e floor ()? Funções trigonométricas?

Lembre-se que int() meramente trunca em direção 0. Para o arredondamento para um determinado número de dígitos, sprintf() ou printf() é geralmente o mais fácil rota.

    printf("%.3f", 3.1415926535);       # prints 3.142

Os POSIX módulo (parte do padrão de distribuição de Perl) implementa ceil(), floor(), e uma série de outras matemáticas e trigonométricas funções.

    use POSIX;
    $ceil   = ceil(3.5);                        # 4
    $floor  = floor(3.5);                       # 3

Em 5.000 a 5.003 Perls, trigonometria foi feito no Math::Complex módulo. Com 5.004, o Math::Trig módulo (parte do Perl padrão distribuição) implementa as funções trigonométricas. internamente usa o Math::Complex módulo e algumas funções pode sair do eixo real no plano complexo, por exemplo o seno inversa de dois.

Arredondamento em aplicações financeiras pode ter implicações sérias, e o método de arredondamento utilizado deve ser especificado com precisão. Nesses casos, provavelmente não vale a pena confiança qualquer arredondamento sistema está sendo usado por Perl, mas em vez disso, implementar a função de arredondamento que você precisa você mesmo.

Para ver por que, observe como você ainda tem um problema no meio do caminho ponto alternância:

    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

Não culpe Perl. É o mesmo que em C. IEEE diz que temos que fazer isto. números Perl cujos valores absolutos são inteiros sob 2**31 (em 32 bit máquinas) vai funcionar muito bem como inteiros matemáticos. Outros números não são garantidos.

Outras dicas

Apesar de não discordar com as respostas complexas sobre marcas metade e assim por diante, para o mais comum (e possivelmente trivial) de Caso de Uso:

my $rounded = int($float + 0.5);

Atualizar

Se é possível para o seu $float a ser negativo, a seguinte variação irá produzir o resultado correto:

my $rounded = int($float + $float/abs($float*2 || 1));

Com este cálculo é arredondado -1,4 a -1 e -1,6 e -2, e zero não explodirá.

Você pode usar um módulo como Math :: Rodada :

use Math::Round;
my $rounded = round( $float );

Ou você pode fazê-lo da maneira crua:

my $rounded = sprintf "%.0f", $float;

Se você decidir usar printf ou sprintf, nota que eles usam o metade Rodada até mesmo 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

perldoc / perlfaq :

Lembre-se que int() meramente trunca em direção a 0. Para o arredondamento para um certo número de dígitos, sprintf() ou printf() é geralmente o caminho mais fácil.

 printf("%.3f",3.1415926535);
 # prints 3.142

O módulo POSIX (parte do padrão de distribuição de Perl) implementos ceil(), floor(), e uma série de outras matemática e funções trigonométricas.

use POSIX;
$ceil  = ceil(3.5); # 4
$floor = floor(3.5); # 3

Em 5.000 a 5.003 Perls, trigonometria foi feito no módulo Math::Complex.

Com 5,004, o módulo Math::Trig (parte do padrão de distribuição de Perl)> implementa as funções trigonométricas.

Internamente ele usa o módulo Math::Complex e algumas funções podem quebrar para fora a partir do eixo real no plano complexo, por exemplo o seno inversa de 2.

Arredondamento em aplicações financeiras pode ter implicações sérias, e o arredondamento método utilizado deve ser especificada com precisão. Nestes casos, provavelmente não vale a pena arredondamento confiança qualquer sistema está sendo usado por Perl, mas em vez disso, implementar a arredondamento função que você precisa-se.

Para ver por que, observe como você ainda tem um problema no meio do caminho ponto alternância:

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

Não culpe Perl. É o mesmo que em C. IEEE diz que temos que fazer isto. números Perl cujos valores absolutos são inteiros com menos de 2 ** 31 (em 32 bit máquinas) vai funcionar muito bem como inteiros matemáticos. Outros números não são garantidos.

Você não precisa de nenhum módulo externo.

$x[0] = 1.2;
$x[1] = 1.7;

foreach (@x){
  print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
  print "\n";
}

Eu pode estar faltando o seu ponto, mas eu pensei que esta era a maneira mais limpa para fazer o mesmo trabalho.

O que isto faz é caminhar através de cada número positivo no elemento, imprimir o número eo número inteiro arredondado no formato que você mencionou. O código concatena respectiva inteiro positivo arredondada apenas com base nas decimais. int ($ _) basicamente arredondamento para baixo o número assim ($ -int ($ )) captura os decimais. Se os decimais são (por definição) estritamente inferior a 0,5, por arredondamento para baixo o número. Se não, round-up, adicionando 1.

A seguir irá números rodada positivos ou negativos para uma determinada posição decimal:

sub round ()
{
    my ($x, $pow10) = @_;
    my $a = 10 ** $pow10;

    return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a);
}

A seguir está uma amostra de cinco maneiras diferentes para somar valores. A primeira é uma forma ingénuos para executar o somatório (e não). A segunda tentativa de usar sprintf(), mas isso também falhar. Os terceiros usos sprintf() com sucesso, enquanto o uso floor($value + 0.5) final, dois (4 e 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

Note que floor($value + 0.5) pode ser substituído por int($value + 0.5) para remover a dependência POSIX.

Os números negativos pode adicionar algumas peculiaridades que as pessoas precisam estar cientes.

printf de estilo se aproxima nos dar números corretos, mas podem resultar em alguns monitores ímpares. Descobrimos que este método (na minha opinião, estupidamente) coloca em um sinal - se é ou não deve ou não. Por exemplo, -0,01 arredondados para uma casa decimal retorna a -0.0, ao invés de apenas 0. Se você estiver indo para fazer a abordagem de estilo printf, e você sabe que você quer sem decimal, %d uso e não %f (quando você precisa decimais, que é quando a tela fica instável).

Embora seja correta e para a matemática não é grande coisa, para exibição apenas parece estranho mostrando algo como "-0.0".

Para o método int, números negativos pode mudar o que você quer como resultado (embora existam alguns argumentos que podem ser feitos eles estão corretos).

O int + 0.5 causa problemas reais com números -negative, a menos que você quer que ele funcione dessa maneira, mas eu imagino que a maioria das pessoas não o fazem. -0.9 provavelmente deve rodada para -1, não 0. Se você sabe que você quer negativo para ser um teto em vez de um piso, então você pode fazê-lo em um forro, caso contrário, você pode querer usar o método int com um menor modificação (isto obviamente só funciona para obter números de volta inteiros:

my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;

A minha solução 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 );

Se você só estão preocupados com a obtenção de um valor inteiro fora de um número de ponto flutuante todo (ou seja 12347,9999 ou 54321,0001), esta abordagem (emprestado e modificada a partir de cima) irá fazer o truque:

my $rounded = floor($float + 0.1); 
cat table |
  perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";' 
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top