- 论坛徽章:
- 0
|
一个朋友的拜托,大致是统计一行各个元素的个数和占该行总个数的百分值,这个本来我是直接sprintf("%0.1f%%",$num)的,
然后他反映说这个百分比的总和有些加起来不是100%呀,然后我改了一下代码,碰到这个不知道怎么解决的问题,只好请perl版的
各位朋友帮忙看一下。。
这里面的问题是,我对数据sprintf取1位小数,但是用加和的时候,显示的是sum=100,而while(sum!=100)却能通过。。
用真实数据的时候居然能找到 sum > 100 and sum < 100.1的行,而本来我是希望数据是一位小数的,我个人的怀疑的方向是
perl的存储数字的方式,可能有错,希望碰到过这方面问题的朋友可以帮忙解答,谢谢。
# 测试的数据
GA GG AA GA GG GA GA GA GA GA AA
AG AA GG AG AA AG AG AG AG AG GG
GG GG GG GG GA GG GG GA GA GG GA
GG GG GG GA GG GG GG GG GG GA GG
GG GG GG GA GA GG GG GA GG GA GA
AA AA AA AA AA AA AG AG AG AG AA
GG GG GG GG AG GG GG AG GG GG GG
AA AG AG AG AG AA AG AA AA AA AA
AA AG AG AG AG AA AG AA AA AA AA
CC CT CT CT CT CC CT CC CC CC CC
GG GG GG GG GG GG GG GG GC GG GG
GA GG AA GA GG GA GA GA GA GA AA
CT CT TT TT TT TT CT TT CC CT CC
AG AA GG AG AA AG AG AG AG AG GG
CC CC CT CC CC CC CC CT CC CC CC
TT TG TG TT TT TT TG TT TT TT TT
CC CC CC CA CC CC CC CC CC CC CC
GG GG GG AG GG GG GG AG GG GG GG
TT TT CT TT CT TT TT TT CT CT TT
GG GG GG GG AG GG AG AG AA AG GG
TT CT CT TT TT TT TT TT TT CT CT
AC CT CT CC AC CC AC AA AA AC CC
CT CC CC CC CC CC CC CT CC CC CC
AA AC CC AC AA CC AC AC AC AA AA
CC CC CT CC CC CC CC CT CC CC CC
TT TT CT TT CT TT TT TT CT CT TT
GG GG GT GG GG TT GT GT GG GG GG
GG GA GG AA AA GA GA GA AA GG GA
CT CT TT TT TT TT CT TT CC CT CC
AA AA AG AA AA AA AA AG AA AG AG
CC CC CC CA CC CC CC CC CC CC CC
GG GG GG GG AG GG AG AG AA AG GG
GG AG GG GG GG GG GG GG GG GG GG
GA GA GG AA GG GA GG GA GA GA GA
CC CC CC CG CG CG CG CC CG CG CG
GT GG GG TT GG GT GT GT GT GT GT
CC CC CC CT CT CT CT CT CT CT CT
TT CC CC CC CC CC CC CC CC CC TT
TT GG GG GG GG GG GG GG GG GG TT
AA AA AA AG AG AG AG AG AG AG AG
AA AG AG AG GG AG GG GG AG AG AG
AC CT CT CC AC CC AC AA AA AC CC
GA AA AA AA AA AA AA AA AA AA GA
AA AA AA AG AG AG AG AG GG AG AG
CTC CC CC CC CC CC CC CC CC CC CTC
AC CC CC CC CC CC CC CC CC CC AC
AA AA AA AG AG AG AG AG GG AG AG
TC CC CC CC CC CC CC CC CC CC TC
CC CC CT CT CC CC CT CT CC CT CC
AA AA AA AG AG AG AG AG GG AG AG
TC CC CC CC CC CC CC CC CC CC TC
CC CC CT CT CC CC CT CT CC CT CC
CC CC CT CT CC CC CT CT CC CT CC
AA CA AA AA AA AA AA AA AA AA AA
GG GA GG GG AA GA GG GA GA GG GG
AA AC AA AA AA AA AA AA AA AA AA
CT CC CC CC CC CC CC CT CC CC CC
AA AG AA AA AA GG AA AA AA AA AA
AA AC AA AA AA AA AA AA AA AA AA
CC CT CC CC CC TT CC CC CC CC CC
GG CG GG GG GG CC GG GG GG GG GG
TT CT TT TT TT CC TT TT TT TT TT
AA GA AA AA AA GG AA AA AA AA AA
GG GG GG GG AG GG AG AG AA AG GG
CC CT CC CC CT CT CT CT CT CT CT
AC AA CC AA CC AC AC CC AC AC AC
CC CT CT CC TT CT CT TT CT CC CC
GG GA GA GG GA GG GG GA AA GA GG
GG GG GG GG GG GG GG GG GG GG GG
GA GA GA GG GG GA GA GG GG GA GG
AC CC CC CC CC CC CC CC CC CC AC
CC CC CC CC TT CT CC CT CT CC CC
# 代码
#!/usr/bin/perl
use strict;
use warnings;
my $file = shift || 'test.data';
open my $fh, "< $file" or die "$!";
while (<$fh>) {
chomp;
my @arr = split;
my %hash = ();
my @info = ();
my @per1 = ();
my @per2 = ();
my @key = ();
my @num = ();
map {$hash{$_}++} @arr;
for my $k (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
my $perc1 = $hash{$k} / ($#arr + 1) * 100;
my $perc2 = sprintf("%0.1f", $perc1);
#my $perc2 = Round($perc1);
push @per1, $perc1;
push @per2, $perc2;
push @key, $k;
push @num, $hash{$k};
}
while (Sum(\@per2) != 100) {
print "$.\t111\t@per2\t".Sum(\@per2)."\n";
if(Sum(\@per2) > 100) {
my @arr = map {abs($per2[$_] / $per1[$_] - 1)} (0 .. $#per2);
my ($n, $p) = Max(\@arr);
$per2[$p] -= 0.1;
}
elsif(Sum(\@per2) < 100) {
my @arr = map {abs($per2[$_] / $per1[$_] - 1)} (0 .. $#per2);
my ($n, $p) = Min(\@arr);
$per2[$p] += 0.1;
}
print "$.\t222\t@per2\t".Sum(\@per2)."\n";
}
}
close $fh;
#----------------------------------------------------------------------------------
sub Round {
my $num = shift;
return int($num * 10 + 0.5) / 10;
}
sub Sum {
my $arr = shift;
my $sum = 0;
map {$sum += $_} @$arr;
return $sum;
}
sub Max {
my $arr = shift;
my $tmp = -9999999999;
my $pos = 0;
for my $i (0 .. $#$arr) {
if($arr->[$i] > $tmp) {
$tmp = $arr->[$i];
$pos = $i;
}
}
return($tmp, $pos);
}
sub Min {
my $arr = shift;
my $tmp = 9999999999;
my $pos = 0;
for my $i (0 .. $#$arr) {
if($arr->[$i] < $tmp) {
$tmp = $arr->[$i];
$pos = $i;
}
}
return($tmp, $pos);
}
# 死循环了
58 111 81.8 9.1 9.1 100
58 222 81.9 9.1 9.1 100.1
58 111 81.9 9.1 9.1 100.1
58 222 81.8 9.1 9.1 100
58 111 81.8 9.1 9.1 100
58 222 81.9 9.1 9.1 100.1
58 111 81.9 9.1 9.1 100.1
58 222 81.8 9.1 9.1 100
58 111 81.8 9.1 9.1 100
58 222 81.9 9.1 9.1 100.1
58 111 81.9 9.1 9.1 100.1
58 222 81.8 9.1 9.1 100
58 111 81.8 9.1 9.1 100
58 222 81.9 9.1 9.1 100.1
58 111 81.9 9.1 9.1 100.1
58 222 81.8 9.1 9.1 100
58 111 81.8 9.1 9.1 100
58 222 81.9 9.1 9.1 100.1
58 111 81.9 9.1 9.1 100.1
58 222 81.8 9.1 9.1 100
58 111 81.8 9.1 9.1 100
58 222 81.9 9.1 9.1 100.1
^C58 111 81.9 9.1 9.1 100.1
|
|