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.142The
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);
Comments