Как вы округляете число с плавающей запятой в Perl?



Как я могу округлить десятичное число (с плавающей точкой) до ближайшего целого?



например



1.2 = 1
1.7 = 2
1038   12  

12 ответов:

выход perldoc -q round

Имеет ли Perl функцию round ()? А как насчет ceil () и floor ()? Тригонометрические функции?

Помните, что int() просто усекает в сторону 0. Для округления до определенного количества цифр, sprintf() или printf() обычно самый простой маршрут.

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

Элемент POSIX модуль (часть стандартного распределения Perl) инвентарь ceil(),floor(), и ряд других математических и тригонометрических функции.

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

В 5.000 до 5.003 perls, тригонометрия была сделана в Math::Complex модуль. С 5.004, в Math::Trig модуль (часть стандартного Perl распределение) реализует тригонометрические функции. Внутренне это использует Math::Complex модуль и некоторые функции могут вырваться из действительной оси в комплексной плоскость, например обратный синус 2.

Округление в финансовых заявках может иметь серьезные последствия, и используемый метод округления должен быть точно указан. В этих в некоторых случаях, вероятно, стоит не доверять какой-либо системе округления используется Perl, но вместо этого реализовать функцию округления вам нужно себе.

Чтобы понять, почему, обратите внимание, как у вас все еще будет проблема полпути-точка чередование:

    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

Не вини Перл. Это то же самое, что и в C. IEEE говорит, что мы должны сделать этот. Числа Perl, абсолютные значения которых являются целыми числами под 2**31 (по 32-битные машины) будут работать в значительной степени как математические целые числа. Другие номера не гарантируются.

не соглашаясь со сложными ответами о метках на полпути и т. д., Для более распространенного (и, возможно, тривиального) варианта использования:

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

обновление

Если это возможно для вашего $float чтобы быть отрицательным, следующий вариант даст правильный результат:

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

при этом вычислении -1.4 округляется до -1, а -1.6 до -2, и ноль не взорвется.

вы можете либо использовать модуль, как Математика::Круглая:

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

или вы можете сделать это грубый способ:

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

Если вы решили использовать printf или sprintf, обратите внимание, что они используют круглая половина до четной метод.

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:

помните, что int() просто усекает к 0. Для округления к определенное количество цифр, sprintf() или printf() обычно легкий путь.

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

The POSIX модуль (часть стандартного распределения Perl) реализует ceil(),floor(), и ряд других математических и тригонометрические функции.

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

в 5.000 до 5.003 perls, тригонометрия была сделано в Math::Complex модуль.

С 5.004, в Math::Trig модуль (часть стандартного распределения Perl) > реализует тригонометрические функции.

внутренне он использует Math::Complex модуль и некоторые функции могут сломать из реальной оси в комплексную плоскость, например, обратный синус 2.

округления в финансовых приложениях может иметь серьезные последствия, и округление используемый метод должен быть точно указан. В в этих случаях, вероятно, не стоит доверяйте тому, какое системное округление используется Perl, но вместо этого реализуйте функция округления вам нужна самостоятельно.

чтобы понять, почему, обратите внимание, как вы все еще будете иметь проблему на полпути точки чередование:

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

не вините Perl. Это то же самое, что и в C. IEEE говорит, что мы должны сделать этот. Числа Perl, абсолютные значения которых являются целыми числами под 2* * 31 (on 32-битные машины) будут работать в значительной степени как математические целые. Другие номера не гарантируются.

вам не нужен никакой внешний модуль.

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

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

возможно, я упускаю вашу точку зрения, но я думал, что это гораздо более чистый способ сделать ту же работу.

что это делает, чтобы пройти через каждое положительное число в элементе, вывести число и округленное целое число в формате, который вы упомянули. Код объединяет соответствующие округленные положительные целые числа только на основе десятичных знаков. int ($_) в основном round-down число so ($ - int($)) захватывает десятичное число. Если десятичные знаки (по определению) строго меньше 0,5, округлите число. Если нет, округление путем добавления 1.

следующие округляют положительные или отрицательные числа до заданной десятичной позиции:

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

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

Ниже приведен пример из пяти различных способов суммирования значений. Первый-это наивный способ выполнить суммирование (и не удается). Вторая попытка использовать sprintf(), но это тоже не удается. Третий использует sprintf() успешно, в то время как последние два (4-й и 5-й) используют 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

отметим, что floor($value + 0.5) можно заменить на int($value + 0.5) чтобы удалить зависимость POSIX.

отрицательные числа могут добавить некоторые причуды, которые люди должны знать.

printfподходы дают нам правильные цифры, но они могут привести к некоторым странным дисплеев. Мы обнаружили, что этот метод (на мой взгляд, тупо) ставит в - знаком ли он должен или не должен. Например, -0.01 округляется до одного знака после запятой возвращает -0.0, а не просто 0. Если вы собираетесь сделать printf стиль подход, и вы знаете, что вы не хотите десятичной, используйте %d и не %f (когда вам нужны десятичные числа, это когда дисплей становится шатким).

хотя это правильно и для математики не имеет большого значения, для отображения это просто выглядит странно, показывая что-то вроде "-0.0".

для метода int отрицательные числа могут изменить то, что вы хотите в результате (хотя есть некоторые аргументы, которые могут быть сделаны, они верны).

The int + 0.5 вызывает реальные проблемы с отрицательными числами, если вы не хотите, чтобы это работало таким образом, но я думаю, что большинство людей нет. -0.9, вероятно, должен округляться до -1, а не 0. Если вы знаете, что хотите, чтобы отрицательный был потолком, а не полом, вы можете сделать это в одном лайнере, иначе вы можете использовать метод int с незначительной модификацией (это, очевидно, работает только для возврата целых чисел:

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

мое решение для sprintf

if ($value =~ m/\d\..*5$/){
    $format =~ /.*(\d)f$/;
    if (defined ){
       my $coef = "0." . "0" x  . "05";    
            $value = $value + $coef;    
    }
}

$value = sprintf( "$format", $value );

Если вас интересует только получение целого значения из целого числа с плавающей запятой (т. е. 12347.9999 или 54321.0001), этот подход (заимствованный и измененный сверху) будет делать трюк:

my $rounded = floor($float + 0.1); 
cat table |
  perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log()/log(2))."\t\n";' 

Comments

    Ничего не найдено.