IT

Perl에서 부동 소수점 숫자를 어떻게 반올림합니까?

lottoking 2020. 5. 27. 07:48
반응형

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모듈 (표준 펄 분포의 일부)을 구현 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을 비난하지 마십시오. IEEE와 마찬가지로 C도 마찬가지다. 절대 값이 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로 반올림되며 0은 폭발하지 않습니다.


Math :: Round 와 같은 모듈을 사용할 수 있습니다 .

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

POSIX모듈 (표준 펄 분포의 일부)을 구현 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).

Rounding in financial applications can have serious implications, and the rounding method used should be specified precisely. In these cases, it probably pays not to trust whichever system rounding is being used by Perl, but to instead implement the rounding function you need yourself.

To see why, notice how you'll still have an issue on half-way-point alternation:

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

Don't blame Perl. It's the same as in C. IEEE says we have to do this. Perl numbers whose absolute values are integers under 2**31 (on 32 bit machines) will work pretty much like mathematical integers. Other numbers are not guaranteed.


You don't need any external module.

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

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

I may be missing your point, but I thought this was much cleaner way to do the same job.

What this does is to walk through every positive number in the element, print the number and rounded integer in the format you mentioned. The code concatenates respective rounded positive integer only based on the decimals. int($_) basically round-down the number so ($-int($)) captures the decimals. If the decimals are (by definition) strictly less than 0.5, round-down the number. If not, round-up by adding 1.


The following will round positive or negative numbers to a given decimal position:

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

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

Following is a sample of five different ways to summate values. The first is a naive way to perform the summation (and fails). The second attempts to use sprintf(), but it too fails. The third uses sprintf() successfully while the final two (4th & 5th) use 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

Note that floor($value + 0.5) can be replaced with int($value + 0.5) to remove the dependency on POSIX.


Negative numbers can add some quirks that people need to be aware of.

printf-style approaches give us correct numbers, but they can result in some odd displays. We have discovered that this method (in my opinion, stupidly) puts in a - sign whether or not it should or shouldn't. For example, -0.01 rounded to one decimal place returns a -0.0, rather than just 0. If you are going to do the printf style approach, and you know you want no decimal, use %d and not %f (when you need decimals, it's when the display gets wonky).

While it's correct and for math no big deal, for display it just looks weird showing something like "-0.0".

For the int method, negative numbers can change what you want as a result (though there are some arguments that can be made they are correct).

The int + 0.5 causes real issues with -negative numbers, unless you want it to work that way, but I imagine most people don't. -0.9 should probably round to -1, not 0. If you know that you want negative to be a ceiling rather than a floor then you can do it in one-liner, otherwise, you might want to use the int method with a minor modification (this obviously only works to get back whole numbers:

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

My solution for 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 );

If you are only concerned with getting an integer value out of a whole floating point number (i.e. 12347.9999 or 54321.0001), this approach (borrowed and modified from above) will do the trick:

my $rounded = floor($float + 0.1); 

cat table |
  perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";' 

참고URL : https://stackoverflow.com/questions/178539/how-do-you-round-a-floating-point-number-in-perl

반응형