Yanıtlar:
Çıktı perldoc -q round
Perl'in round () işlevi var mı? Ceil () ve floor () ne olacak? Trig fonksiyonları?Unutmayın,
int()
sadece kısalır0
. Belirli bir sayıya yuvarlamak içinsprintf()
veyaprintf()
genellikle en kolay yoldur.
printf("%.3f", 3.1415926535); # prints 3.142
POSIX
Modül (standart Perl dağıtım parçası) uygularceil()
,floor()
ve diğer matematiksel ve trigonometrik fonksiyonların bir dizi.
use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
5.000 ila 5.003 perls değerinde,
Math::Complex
modülde trigonometri yapıldı . 5.004 ileMath::Trig
modül (standart Perl dağılımının bir parçası) trigonometrik fonksiyonları uygular. Dahili olarakMath::Complex
modülü kullanır ve bazı işlevler gerçek eksenden karmaşık düzleme girebilir, örneğin 2'nin ters sinüsü.Finansal uygulamalarda yuvarlamanın ciddi sonuçları olabilir ve kullanılan yuvarlama yöntemi tam olarak belirtilmelidir. Bu durumlarda, muhtemelen Perl tarafından hangi sistem yuvarlama kullanılıyorsa güvenmemek, bunun yerine kendinize ihtiyacınız olan yuvarlama işlevini uygulamak için ödeme yapar.
Nedenini görmek için, yarım nokta değişimi konusunda nasıl bir sorununuz olduğunu görün:
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'i suçlama. C ile aynı. IEEE bunu yapmak zorunda olduğumuzu söylüyor. Mutlak değerleri
2**31
(32 bit makinelerde) altında tamsayı olan Perl sayıları, matematiksel tamsayılara çok benzer şekilde çalışır. Diğer numaralar garanti edilmez.
printf
bir değişkente sonuç istiyorsanız kullanmayı deneyin , kullanın sprintf
... Umarım bu size hata ayıklama süresi kazandırır :-P
int()
PDL'lerde kullanabilir miyim ?
Daha çok (ve muhtemelen önemsiz) kullanım durumu için, yarım yol işaretleri ve benzerleri hakkındaki karmaşık cevaplara katılmamaya rağmen:
my $rounded = int($float + 0.5);
GÜNCELLEME
$float
Negatif olmanız mümkünse , aşağıdaki varyasyon doğru sonucu verecektir:
my $rounded = int($float + $float/abs($float*2 || 1));
Bu hesaplama ile -1.4, -1'e ve -1.6 ila -2'ye yuvarlanır ve sıfır patlamaz.
Math :: Round gibi bir modül kullanabilirsiniz :
use Math::Round;
my $rounded = round( $float );
Ya da ham yolu yapabilirsiniz:
my $rounded = sprintf "%.0f", $float;
Printf veya sprintf kullanmaya karar verirseniz, bunların çift yarıyı eşitleme yöntemini kullandıklarını unutmayı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
Bkz. Perldoc / perlfaq :
int()
Sadece 0'a doğru kesildiğini unutmayın. Belirli sayıda basamağa yuvarlamak içinsprintf()
veyaprintf()
genellikle en kolay yoldur.printf("%.3f",3.1415926535); # prints 3.142
POSIX
Modül (standart Perl dağıtım parçası) uygularceil()
,floor()
ve diğer matematiksel ve trigonometrik fonksiyonların bir dizi.use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
5.000 ila 5.003 perls değerinde,
Math::Complex
modülde trigonometri yapıldı .5.004 ile
Math::Trig
modül (standart Perl dağılımının bir parçası)> trigonometrik fonksiyonları uygular.Dahili olarak
Math::Complex
modülü kullanır ve bazı işlevler gerçek eksenden karmaşık düzleme girebilir, örneğin 2'nin ters sinüsü.Finansal uygulamalarda yuvarlamanın ciddi sonuçları olabilir ve kullanılan yuvarlama yöntemi tam olarak belirtilmelidir. Bu durumlarda, muhtemelen Perl tarafından hangi sistem yuvarlama kullanılıyorsa güvenmemek, bunun yerine kendinize ihtiyacınız olan yuvarlama işlevini uygulamak için ödeme yapar.
Nedenini görmek için, yarım nokta değişimi konusunda nasıl bir sorununuz olduğunu görün:
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'i suçlama. C ile aynı. IEEE bunu yapmak zorunda olduğumuzu söylüyor. Mutlak değerleri 2 ** 31 (32 bit makinelerde) altında tamsayı olan Perl sayıları, matematiksel tamsayılara çok benzer şekilde çalışır. Diğer numaralar garanti edilmez.
Harici bir modüle ihtiyacınız yoktur.
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
print "\n";
}
Senin fikrini kaçırıyor olabilirim, ama bunun aynı işi yapmanın çok daha temiz bir yolu olduğunu düşündüm.
Bunun yaptığı, öğedeki her pozitif sayıdan geçmek, sayıyı ve yuvarlanmış tamsayıyı belirttiğiniz biçimde yazdırmaktır. Kod, yalnızca ondalık sayılara dayalı olarak karşılık gelen yuvarlak pozitif tamsayıyı birleştirir. int ($ _) temel olarak sayıyı aşağı yuvarlar, böylece ($ -int ($ )) ondalık sayıları yakalar. Ondalık sayılar (tanım gereği) kesinlikle 0,5'ten küçükse sayıyı yuvarlayın. Değilse, 1 ekleyerek yuvarlayın.
Aşağıda değerleri özetlemenin beş farklı yolunun bir örneği verilmiştir. Birincisi, toplamı gerçekleştirmenin naif bir yoludur (ve başarısız olur). İkincisi kullanmaya çalışır sprintf()
, ancak başarısız olur. Üçüncüsü sprintf()
başarıyla, son iki (4. ve 5.) kullanılır 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
Bağımlılığı kaldırmak için floor($value + 0.5)
bununla değiştirilebileceğini unutmayın .int($value + 0.5)
POSIX
Negatif sayılar, insanların bilmeleri gereken bazı tuhaflıklar ekleyebilir.
printf
tarzı yaklaşımlar bize doğru sayılar verir, ancak bazı garip görüntülerle sonuçlanabilir. Bu yöntemin (bence, aptalca), -
yapması gerekip gerekmediğine dair bir işaret koyduğunu keşfettik . Örneğin, bir ondalık basamağa yuvarlanmış -0,01 yalnızca 0 yerine bir -0,0 döndürür. printf
Stil yaklaşımını yapacaksanız ve ondalık basamak istemediğinizi biliyorsanız, kullanmayın %d
ve kullanmayın %f
(ondalıklara ihtiyacınız olduğunda, görüntü sakat olur).
Doğru ve matematik için önemli bir şey olmasa da, görüntülemek için sadece "-0.0" gibi bir şey göstermek garip görünüyor.
İnt yöntemi için, negatif sayılar sonuç olarak ne istediğinizi değiştirebilir (doğru olmaları için yapılabilecek bazı argümanlar olsa da).
Bu int + 0.5
şekilde çalışmasını istemediğiniz sürece -negatif sayılarla gerçek sorunlara neden olur, ancak çoğu insanın işe yaramadığını hayal ediyorum. -0.9 muhtemelen 0 değil, -1'e yuvarlanmalıdır. Negatifin bir kattan ziyade bir tavan olmasını istediğinizi biliyorsanız, o zaman bir astarda yapabilirsiniz, aksi takdirde, int yöntemini bir minörle kullanmak isteyebilirsiniz. değişiklik (bu sadece tam sayıları geri almak için çalışır:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
Yalnızca tam bir kayan nokta sayısından (yani 12347.9999 veya 54321.0001) bir tam sayı değeri elde etmekle ilgileniyorsanız, bu yaklaşım (yukarıdan ödünç alınmış ve değiştirilmiş) hile yapacaktır:
my $rounded = floor($float + 0.1);
sayıların nasıl yuvarlanacağına dair birçok okuma belgesi, birçok uzman kendi yuvarlama rutinlerinizi yazmanızı önerir, çünkü dilinizle birlikte verilen 'hazır' sürüm yeterince hassas olmayabilir veya hatalar içerebilir. Ancak, sadece bir, iki veya üç değil, ondalık basamaklardan bahsettiklerini hayal ediyorum. akılda tutulması gereken, benim çözümüm (her ne kadar TAMAMEN talep edilmediğim gibi dolar göstermek için olsa da - süreç çok farklı değil).
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]++; } } }
bu yüzden: if ($digit1 >= 5) { $digit1 = 0; $cost[0]++; }
o zaman sadecereturn commafied($cost[0]);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'