免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3017 | 回复: 1
打印 上一主题 下一主题

关于perl数值比较的疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-06-20 15:56 |只看该作者 |倒序浏览
一个朋友的拜托,大致是统计一行各个元素的个数和占该行总个数的百分值,这个本来我是直接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



论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
2 [报告]
发表于 2016-06-20 17:32 |只看该作者
本帖最后由 jason680 于 2016-06-20 17:47 编辑

回复 1# flyingdancen

>> ...这个百分比的总和有些加起来不是100%呀...
>> ...perl的存储数字的方式,可能有错,...

1. 这是准确度问题与Perl的无关

2. 准确度accuracy  http://baike.baidu.com/view/434085.htm
指在一定实验条件下多次测定的平均值与真值相符合的程度,以误差来表示。它用来表示系统误差的大小。在实际工作中,通常用标准物质或标准方法进行对照试验,在无标准物质或标准方法时,常用加入被测定组分的纯物质进行回收试验来估计和确定准确度。...

3. 试想一个问题
GA,AA,AG
GA=1/3=33.3%
AA =1/3=33.3%
AG=1/3=33.3%
总合1/3+1/3+1/3= 33.3% + 33.3% + 33.3% = 99.9%
若为1/5+... +1/5=20.0%+... +20.0%=20.0%* 5=100.0%
若为1/7+... +1/7=14.3%+... +14.3%=14.3%* 7=100.1%

注:1/3=33.3333333...%
1/5=20%
1/7=14.285714285...%
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP