Jawaban:
Output dari perldoc -q round
Apakah Perl memiliki fungsi round ()? Bagaimana dengan ceil () dan floor ()? Fungsi trigonometri?Ingatlah bahwa
int()
hanya memotong ke arah0
. Untuk pembulatan ke angka tertentu,sprintf()
atauprintf()
biasanya rute termudah.
printf("%.3f", 3.1415926535); # prints 3.142
The
POSIX
modul (bagian dari distribusi Perl standar) menerapkanceil()
,floor()
dan sejumlah fungsi matematika dan trigonometri lainnya.
use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
Dalam 5.000 hingga 5.003 perl, trigonometri dilakukan dalam
Math::Complex
modul. Dengan 5.004,Math::Trig
modul (bagian dari distribusi Perl standar) mengimplementasikan fungsi trigonometri. Secara internal ia menggunakanMath::Complex
modul dan beberapa fungsi dapat keluar dari sumbu nyata ke bidang kompleks, misalnya sinus terbalik 2.Pembulatan dalam aplikasi keuangan dapat memiliki implikasi serius, dan metode pembulatan yang digunakan harus ditentukan secara tepat. Dalam kasus ini, mungkin membayar untuk tidak mempercayai pembulatan sistem mana pun yang digunakan oleh Perl, tetapi untuk mengimplementasikan fungsi pembulatan yang Anda butuhkan sendiri.
Untuk mengetahui alasannya, perhatikan bagaimana Anda masih akan memiliki masalah tentang pergantian setengah jalan:
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
Jangan salahkan Perl. Itu sama dengan di C. IEEE mengatakan kita harus melakukan ini. Bilangan perl yang nilai absolutnya adalah bilangan bulat di bawah
2**31
(pada mesin 32 bit) akan berfungsi seperti bilangan bulat matematika. Nomor lain tidak dijamin.
printf
jika Anda ingin hasil dalam variabel, gunakan sprintf
... harap ini menghemat waktu debugging :-P
int()
PDL?
Meskipun tidak setuju dengan jawaban kompleks tentang tanda setengah jalan dan seterusnya, untuk kasus penggunaan yang lebih umum (dan mungkin sepele):
my $rounded = int($float + 0.5);
MEMPERBARUI
Jika Anda $float
mungkin negatif, variasi berikut akan menghasilkan hasil yang benar:
my $rounded = int($float + $float/abs($float*2 || 1));
Dengan perhitungan ini, -1.4 dibulatkan menjadi -1, dan -1.6 hingga -2, dan nol tidak akan meledak.
Anda bisa menggunakan modul seperti Math :: Round :
use Math::Round;
my $rounded = round( $float );
Atau Anda bisa melakukannya dengan cara kasar:
my $rounded = sprintf "%.0f", $float;
Jika Anda memutuskan untuk menggunakan printf atau sprintf, perhatikan bahwa mereka menggunakan metode 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
Lihat perldoc / perlfaq :
Ingatlah bahwa
int()
hanya memotong menuju 0. Untuk membulatkan ke angka tertentu,sprintf()
atauprintf()
biasanya merupakan rute termudah.printf("%.3f",3.1415926535); # prints 3.142
The
POSIX
modul (bagian dari distribusi Perl standar) menerapkanceil()
,floor()
dan sejumlah fungsi matematika dan trigonometri lainnya.use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
Dalam 5.000 hingga 5.003 perl, trigonometri dilakukan dalam
Math::Complex
modul.Dengan 5,004,
Math::Trig
modul (bagian dari distribusi Perl standar)> mengimplementasikan fungsi trigonometri.Secara internal ia menggunakan
Math::Complex
modul dan beberapa fungsi dapat keluar dari sumbu nyata ke bidang kompleks, misalnya sinus terbalik 2.Pembulatan dalam aplikasi keuangan dapat memiliki implikasi serius, dan metode pembulatan yang digunakan harus ditentukan secara tepat. Dalam kasus ini, mungkin membayar untuk tidak mempercayai pembulatan sistem mana pun yang digunakan oleh Perl, tetapi untuk mengimplementasikan fungsi pembulatan yang Anda butuhkan sendiri.
Untuk mengetahui alasannya, perhatikan bagaimana Anda masih akan memiliki masalah tentang pergantian setengah jalan:
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
Jangan salahkan Perl. Itu sama dengan di C. IEEE mengatakan kita harus melakukan ini. Bilangan perl yang nilai absolutnya adalah bilangan bulat di bawah 2 ** 31 (pada mesin 32 bit) akan berfungsi seperti halnya bilangan bulat matematika. Nomor lain tidak dijamin.
Anda tidak memerlukan modul eksternal apa pun.
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
print "\n";
}
Saya mungkin kehilangan poin Anda, tetapi saya pikir ini adalah cara yang jauh lebih bersih untuk melakukan pekerjaan yang sama.
Apa yang dilakukan adalah menelusuri setiap angka positif dalam elemen, mencetak angka dan bilangan bulat bulat dalam format yang Anda sebutkan. Kode ini menyatukan masing-masing bilangan bulat positif bulat hanya berdasarkan desimal. int ($ _) pada dasarnya membulatkan angka jadi ($ -int ($ )) menangkap desimal. Jika desimalnya (menurut definisi) benar-benar kurang dari 0,5, bulatkan jumlahnya. Jika tidak, bulatkan dengan menambahkan 1.
Berikut ini adalah contoh lima cara berbeda untuk merangkum nilai. Yang pertama adalah cara naif untuk melakukan penjumlahan (dan gagal). Upaya kedua untuk digunakan sprintf()
, tetapi juga gagal. Penggunaan ketiga sprintf()
berhasil sementara dua terakhir (4 & 5) digunakan 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
Catatan yang floor($value + 0.5)
dapat diganti dengan int($value + 0.5)
untuk menghapus ketergantungan POSIX
.
Angka negatif dapat menambahkan beberapa kebiasaan yang perlu diperhatikan orang.
printf
Pendekatan gaya memberi kita angka yang benar, tetapi mereka dapat menghasilkan beberapa tampilan aneh. Kami telah menemukan bahwa metode ini (menurut saya, bodoh) memberi -
tanda apakah harus atau tidak seharusnya. Misalnya, -0,01 dibulatkan ke satu tempat desimal mengembalikan -0,0, bukan hanya 0. Jika Anda akan melakukan printf
pendekatan gaya, dan Anda tahu Anda ingin tidak ada desimal, gunakan %d
dan tidak %f
(ketika Anda membutuhkan desimal, saat itulah tampilan menjadi miring).
Meskipun benar dan untuk matematika bukan masalah besar, untuk tampilan itu hanya terlihat aneh menunjukkan sesuatu seperti "-0.0".
Untuk metode int, angka negatif dapat mengubah apa yang Anda inginkan sebagai hasilnya (meskipun ada beberapa argumen yang dapat membuatnya benar).
The int + 0.5
menyebabkan masalah nyata dengan nomor -negatif, kecuali jika Anda ingin bekerja seperti itu, tapi aku membayangkan kebanyakan orang tidak. -0,9 mungkin harus dibulatkan menjadi -1, bukan 0. Jika Anda tahu bahwa Anda ingin negatif menjadi langit-langit daripada lantai maka Anda dapat melakukannya dalam satu-liner, jika tidak, Anda mungkin ingin menggunakan metode int dengan minor modifikasi (ini jelas hanya berfungsi untuk mendapatkan kembali bilangan bulat:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
Jika Anda hanya peduli untuk mendapatkan nilai integer dari angka floating point keseluruhan (yaitu 12347.9999 atau 54321.0001), pendekatan ini (dipinjam dan dimodifikasi dari atas) akan melakukan trik:
my $rounded = floor($float + 0.1);
banyak membaca dokumentasi tentang cara membulatkan angka, banyak ahli menyarankan untuk menulis rutinitas pembulatan Anda sendiri, karena versi 'kalengan' yang disediakan dengan bahasa Anda mungkin tidak cukup tepat, atau mengandung kesalahan. Saya membayangkan, bagaimanapun, mereka berbicara banyak tempat desimal bukan hanya satu, dua, atau tiga. dengan itu dalam pikiran, inilah solusi saya (walaupun tidak PERSIS seperti yang diminta karena kebutuhan saya untuk menampilkan dolar - prosesnya tidak jauh berbeda, meskipun).
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]++; } } }
jadi: if ($digit1 >= 5) { $digit1 = 0; $cost[0]++; }
kemudian sajareturn commafied($cost[0]);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'