Как вы объедините число с плавающей запятой в Perl?

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

например

1.2 = 1 1.7 = 2 

Выход 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 

Не обвиняйте Perl. Это то же самое, что и в 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, а нуль не будет взорваться.

Вы можете использовать модуль Math :: Round :

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

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

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

Если вы решите использовать printf или sprintf, обратите внимание, что они используют метод Round half to even .

 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 

Модуль 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 (на 32-битных машинах), будут работать почти так же, как математические целые числа. Другие номера не гарантируются.

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

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

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

Для этого нужно пройти через каждое положительное число в элементе, напечатать число и округленное целое число в указанном вами формате. Код объединяет соответствующее округленное положительное целое число только на основе десятичных знаков. int ($ _) в основном округляет число так ($ -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() успешно, в то время как последние два (четвертый и пятый) используют 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 style дают нам правильные номера, но они могут приводить к некоторым нечетным отображениям. Мы обнаружили, что этот метод (по-моему, глупо) ставит в знак того, следует или нет. Например, -0.01, округленное до одного десятичного знака, возвращает значение -0.0, а не только 0. Если вы собираетесь использовать подход стиля printf , и вы знаете, что вы не хотите десятичного числа, используйте %d а не %f (если вам нужно десятичные знаки, это когда дисплей становится неуклюжим).

Хотя это правильно и для математики не имеет большого значения, для отображения это просто выглядит странно, показывая что-то вроде «-0,0».

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

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 $1){ my $coef = "0." . "0" x $1 . "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($1)/log(2))."\t$2\n";' 
  • Как временные среды Java, нацеленные на процессоры pre-SSE2, реализуют базовые операции с плавающей запятой?
  • Сравнение поплавковых и двойных типов данных в объекте C
  • Android Как реализовать нижний лист из документации по материальному дизайну
  • Как преобразовать целое число в float в Java?
  • double или float, что быстрее?
  • Почему значение с плавающей запятой, такое как 3.14, по умолчанию считается в MSVC?
  • Библиотека высокой точности с плавающей запятой Java
  • Разница между десятичной, плавающей и двойной в .NET?
  • Преобразовать число с плавающей запятой в определенную точность, а затем скопировать в строку
  • Разница в арифметике с плавающей запятой между x86 и x64
  • Как я могу написать функцию питания самостоятельно?
  • Давайте будем гением компьютера.