Làm cách nào tôi có thể làm tròn số thập phân (dấu phẩy động) sang số nguyên gần nhất?
ví dụ
1.2 = 1
1.7 = 2
Làm cách nào tôi có thể làm tròn số thập phân (dấu phẩy động) sang số nguyên gần nhất?
ví dụ
1.2 = 1
1.7 = 2
Câu trả lời:
Đầu ra của perldoc -q round
Perl có hàm round () không? Còn trần () và sàn () thì sao? Chức năng trig?Hãy nhớ rằng
int()
chỉ đơn giản là cắt ngắn về phía0
. Để làm tròn đến một số chữ số nhất định,sprintf()
hoặcprintf()
thường là con đường dễ nhất.
printf("%.3f", 3.1415926535); # prints 3.142
Các
POSIX
mô-đun (một phần của phân phối Perl tiêu chuẩn) dụng cụceil()
,floor()
và một số chức năng toán học và lượng giác khác.
use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
Trong 5.000 đến 5,003 perls, lượng giác đã được thực hiện trong
Math::Complex
mô-đun. Với 5,004,Math::Trig
mô-đun (một phần của phân phối Perl tiêu chuẩn) thực hiện các hàm lượng giác. Trong nội bộ, nó sử dụngMath::Complex
mô-đun và một số chức năng có thể thoát ra khỏi trục thực vào mặt phẳng phức, ví dụ sin ngược của 2.Làm tròn trong các ứng dụng tài chính có thể có ý nghĩa nghiêm trọng và phương pháp làm tròn được sử dụng phải được chỉ định chính xác. Trong những trường hợp này, có thể trả tiền không tin tưởng bất kỳ hệ thống làm tròn nào đang được Perl sử dụng, mà thay vào đó để thực hiện chức năng làm tròn mà bạn cần cho mình.
Để biết lý do tại sao, hãy chú ý cách bạn vẫn gặp sự cố khi thay đổi nửa điểm:
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
Đừng đổ lỗi cho Perl. Nó giống như trong C. IEEE nói rằng chúng ta phải làm điều này. Các số Perl có giá trị tuyệt đối là số nguyên dưới
2**31
(trên máy 32 bit) sẽ hoạt động khá giống với số nguyên toán học. Các số khác không được đảm bảo.
printf
nếu bạn muốn kết quả trong một biến, hãy sử dụng sprintf
... hy vọng điều này sẽ giúp bạn tiết kiệm thời gian gỡ lỗi :-P
int()
trên PDL không?
Mặc dù không đồng ý với các câu trả lời phức tạp về các dấu hiệu nửa vời, v.v., đối với trường hợp sử dụng phổ biến hơn (và có thể tầm thường):
my $rounded = int($float + 0.5);
CẬP NHẬT
Nếu bạn $float
có thể âm tính, biến thể sau đây sẽ tạo ra kết quả chính xác:
my $rounded = int($float + $float/abs($float*2 || 1));
Với phép tính này, .41.4 được làm tròn thành -1 và -1.6 đến -2 và không nổ.
Bạn có thể sử dụng một mô-đun như Math :: Round :
use Math::Round;
my $rounded = round( $float );
Hoặc bạn có thể làm theo cách thô thiển:
my $rounded = sprintf "%.0f", $float;
Nếu bạn quyết định sử dụng printf hoặc sprintf, lưu ý rằng họ sử dụng phương pháp Round Half để chẵn .
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
Xem perldoc / perlfaq :
Hãy nhớ rằng
int()
chỉ đơn giản là cắt ngắn về 0. Để làm tròn đến một số chữ số nhất định,sprintf()
hoặcprintf()
thường là con đường dễ nhất.printf("%.3f",3.1415926535); # prints 3.142
Các
POSIX
mô-đun (một phần của phân phối Perl tiêu chuẩn) dụng cụceil()
,floor()
và một số chức năng toán học và lượng giác khác.use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
Trong 5.000 đến 5,003 perls, lượng giác đã được thực hiện trong
Math::Complex
mô-đun.Với 5,004,
Math::Trig
mô-đun (một phần của phân phối Perl tiêu chuẩn)> thực hiện các hàm lượng giác.Trong nội bộ, nó sử dụng
Math::Complex
mô-đun và một số chức năng có thể thoát ra khỏi trục thực vào mặt phẳng phức, ví dụ sin ngược của 2.Làm tròn trong các ứng dụng tài chính có thể có ý nghĩa nghiêm trọng và phương pháp làm tròn được sử dụng phải được chỉ định chính xác. Trong những trường hợp này, có thể trả tiền không tin tưởng bất kỳ hệ thống làm tròn nào đang được Perl sử dụng, mà thay vào đó để thực hiện chức năng làm tròn mà bạn cần cho mình.
Để biết lý do tại sao, hãy chú ý cách bạn vẫn gặp sự cố khi thay đổi nửa điểm:
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
Đừng đổ lỗi cho Perl. Nó giống như trong C. IEEE nói rằng chúng ta phải làm điều này. Các số Perl có giá trị tuyệt đối là số nguyên dưới 2 ** 31 (trên máy 32 bit) sẽ hoạt động khá giống với số nguyên toán học. Các số khác không được đảm bảo.
Bạn không cần bất kỳ mô-đun bên ngoài.
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
print "\n";
}
Tôi có thể thiếu quan điểm của bạn, nhưng tôi nghĩ rằng đây là cách sạch sẽ hơn nhiều để làm cùng một công việc.
Điều này làm là đi qua mọi số dương trong phần tử, in số và số nguyên được làm tròn theo định dạng bạn đã đề cập. Mã nối các số nguyên dương được làm tròn tương ứng chỉ dựa trên số thập phân. int ($ _) về cơ bản làm tròn số để so ($ -int ($ )) nắm bắt các số thập phân. Nếu số thập phân là (theo định nghĩa) đúng nhỏ hơn 0,5, làm tròn số. Nếu không, làm tròn bằng cách thêm 1.
Sau đây sẽ làm tròn các số dương hoặc âm đến một vị trí thập phân nhất định:
sub round ()
{
my ($x, $pow10) = @_;
my $a = 10 ** $pow10;
return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a);
}
Sau đây là một mẫu của năm cách khác nhau để tổng hợp các giá trị. Đầu tiên là một cách ngây thơ để thực hiện tổng kết (và thất bại). Lần thử thứ hai để sử dụng sprintf()
, nhưng nó quá thất bại. Cái thứ ba sử dụng sprintf()
thành công trong khi hai cái cuối cùng (thứ 4 & 5) sử dụng 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
Lưu ý rằng floor($value + 0.5)
có thể được thay thế bằng int($value + 0.5)
để loại bỏ sự phụ thuộc vào POSIX
.
Số âm có thể thêm một số quirks mà mọi người cần phải nhận thức được.
printf
phương pháp tiếp cận kiểu cho chúng ta số chính xác, nhưng chúng có thể dẫn đến một số màn hình kỳ lạ. Chúng tôi đã phát hiện ra rằng phương pháp này (theo ý kiến của tôi, một cách ngu ngốc) đưa vào một -
dấu hiệu cho dù nó nên hay không nên. Ví dụ: -0,01 được làm tròn đến một vị trí thập phân trả về -0.0, thay vì chỉ 0. Nếu bạn định thực hiện printf
phương pháp kiểu và bạn biết bạn không muốn số thập phân, hãy sử dụng %d
và không %f
(khi bạn cần số thập phân, đó là khi hiển thị trở nên mạnh mẽ).
Mặc dù nó đúng và đối với toán học không phải là vấn đề lớn, để hiển thị, nó trông có vẻ kỳ lạ khi hiển thị một cái gì đó như "-0.0".
Đối với phương thức int, các số âm có thể thay đổi kết quả bạn muốn (mặc dù có một số đối số có thể được thực hiện chúng là chính xác).
Các int + 0.5
nguyên nhân gây các vấn đề thực sự với số -phủ định, trừ khi bạn muốn nó hoạt động theo cách đó, nhưng tôi tưởng tượng hầu hết mọi người thì không. -0.9 có lẽ nên làm tròn thành -1, không phải 0. Nếu bạn biết rằng bạn muốn âm là trần chứ không phải là sàn thì bạn có thể thực hiện trong một lớp lót, nếu không, bạn có thể muốn sử dụng phương thức int với một phụ sửa đổi (điều này rõ ràng chỉ hoạt động để lấy lại toàn bộ số:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
Nếu bạn chỉ quan tâm đến việc lấy một giá trị số nguyên trong toàn bộ số dấu phẩy động (ví dụ 12347.9999 hoặc 54321.0001), phương pháp này (mượn và sửa đổi từ trên) sẽ thực hiện thủ thuật:
my $rounded = floor($float + 0.1);
vô số tài liệu đọc về cách làm tròn số, nhiều chuyên gia khuyên bạn nên viết thói quen làm tròn của riêng bạn, vì phiên bản 'đóng hộp' được cung cấp với ngôn ngữ của bạn có thể không đủ chính xác hoặc có lỗi. tôi tưởng tượng, tuy nhiên, họ đang nói nhiều vị trí thập phân không chỉ một, hai hoặc ba. với ý nghĩ đó, đây là giải pháp của tôi (mặc dù không chính xác như yêu cầu vì nhu cầu của tôi là hiển thị đô la - tuy nhiên quá trình này không khác nhiều).
sub asDollars($) {
my ($cost) = @_;
my $rv = 0;
my $negative = 0;
if ($cost =~ /^-/) {
$negative = 1;
$cost =~ s/^-//;
}
my @cost = split(/\./, $cost);
# let's get the first 3 digits of $cost[1]
my ($digit1, $digit2, $digit3) = split("", $cost[1]);
# now, is $digit3 >= 5?
# if yes, plus one to $digit2.
# is $digit2 > 9 now?
# if yes, $digit2 = 0, $digit1++
# is $digit1 > 9 now??
# if yes, $digit1 = 0, $cost[0]++
if ($digit3 >= 5) {
$digit3 = 0;
$digit2++;
if ($digit2 > 9) {
$digit2 = 0;
$digit1++;
if ($digit1 > 9) {
$digit1 = 0;
$cost[0]++;
}
}
}
$cost[1] = $digit1 . $digit2;
if ($digit1 ne "0" and $cost[1] < 10) { $cost[1] .= "0"; }
# and pretty up the left of decimal
if ($cost[0] > 999) { $cost[0] = commafied($cost[0]); }
$rv = join(".", @cost);
if ($negative) { $rv = "-" . $rv; }
return $rv;
}
sub commafied($) {
#*
# to insert commas before every 3rd number (from the right)
# positive or negative numbers
#*
my ($num) = @_; # the number to insert commas into!
my $negative = 0;
if ($num =~ /^-/) {
$negative = 1;
$num =~ s/^-//;
}
$num =~ s/^(0)*//; # strip LEADING zeros from given number!
$num =~ s/0/-/g; # convert zeros to dashes because ... computers!
if ($num) {
my @digits = reverse split("", $num);
$num = "";
for (my $i = 0; $i < @digits; $i += 3) {
$num .= $digits[$i];
if ($digits[$i+1]) { $num .= $digits[$i+1]; }
if ($digits[$i+2]) { $num .= $digits[$i+2]; }
if ($i < (@digits - 3)) { $num .= ","; }
if ($i >= @digits) { last; }
}
#$num =~ s/,$//;
$num = join("", reverse split("", $num));
$num =~ s/-/0/g;
}
if ($negative) { $num = "-" . $num; }
return $num; # a number with commas added
#usage: my $prettyNum = commafied(1234567890);
}
if ($digit3 >= 5) { $digit3 = 0; $digit2++; if ($digit2 > 9) { $digit2 = 0; $digit1++; if ($digit1 > 9) { $digit1 = 0; $cost[0]++; } } }
vì vậy: if ($digit1 >= 5) { $digit1 = 0; $cost[0]++; }
đó làreturn commafied($cost[0]);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'