标题:求优化下程序,这个程序能用,就是运行太慢,求优化下能加快速度
只看楼主
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
uint32 能表示的最大值为 4294967295,也就是不足43亿。如果用uint64,那就可以表示一千八百亿亿,足够你用了
程序代码:
#include <stdio.h>
#include <string.h>
#include <assert.h>

void dna8_val2str( unsigned long val, char str[8] )
{
    assert( val < (1ul<<(8*2)) );

    for( size_t i=0; i<8; ++i )
    {
        str[7-i] = "agct"[val%4];
        val >>= 2;
    }
}

const char* ifilename = "result1.txt";
const char* ofilename = "result2.txt";

int main()
{
    unsigned long long words = 0;
    unsigned long long numbers[65536] = { 0 };

    // 处理
    FILE* fin = fopen( ifilename, "r" );
    if( !fin )
    {
        printf( "Cannot open \"%s'.\n", ifilename );
        return 1;
    }
    int bav = 0;
    unsigned long val = 0;
    for( int c; c=fgetc(fin), c!=EOF; )
    {
        switch( c )
        {
        case '@': // 遇到@则结束
            break;
        case '\r':
        case '\n':
            ++words;
            //bav = 0;
            continue;
        case 'a':
        case 'g':
        case 'c':
        case 't':
            val = ((val<<2)&0xFFFF) | (c%36%5);
            if(bav<7) // 不足8个有效字符时先等等
                ++bav;
            else
                ++numbers[val];
            break;
        default: // 出现了agct之外的字符
            {
            fpos_t pos;
            fgetpos( fin, &pos );
            if( c>0x20 && c<0xFF ) // 可显示的字符,就显示其本身
                printf( "--- 0x%016llX处出现非法字符\'%c\'\n", pos-1, (char)c );
            else // 不可显示的字符,就显示其对应的ASCII值
                printf( "--- 0x%016llX处出现非法字符0x%02hhX\n", pos-1, (char)c );
            }
        }
    }
    fclose( fin );

    // 输出
    FILE* fout = fopen( ofilename, "w" );
    if( !fout )
    {
        printf( "Cannot open \"%s'.\n", ofilename );
        return 3;
    }
    fprintf( fout, "The Number of total words are %lld\n", words );
    fprintf( fout,"The Expect Number words are %f\n", words/65536.0 );
    for( int i=0; i<65536; ++i )
    {
        // if( numbers[i] !=0 )
        {
            char str[8];
            dna8_val2str( i, str );
            fprintf( fout, "%.8s\t%lld\t%f\n", str, numbers[i], numbers[i]/65536.0 );
        }
    }
    fclose( fout );
    printf( "处理完毕\n" );

    return 0;
}

不过,我最大的疑惑还是10楼说的,对于
aaaaaaaaa
aaaaaaaag
aaaaaaaac
@
你一开始的代码计算出 aaaaaaaa 数目为 4
后来在7楼又说数目应该为10
其实我觉得,你一开始(为4)才是符合逻辑的,你去问问同事到底应该怎么算
2012-11-15 09:11
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 31楼 rjsp
按道理是后者,等于10才对,不过数据特别大,我做的是统计,所以这点误差可以不考虑了。你最后发的这个代码我刚才运行了一下,
unsigned long long words = 0;
unsigned long long numbers[65536] = { 0 };这两行报错:e:\species\mouse\cpp2.cpp(21) : error C2632: 'long' followed by 'long' is illegal


2012-11-15 09:31
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
行与行的数据是独立的,比如一条基因是 acgttgca,打断成 tgca、acgt,放在你的result1.txt中就是
tgca
acgt
@
如果你下一行接上一行的数据,那就成了 tgcaacgt,明显跟原先的不同

而关于编译不通过,说明你用的编译器“极度”老旧,连 long long 这个C/C++都有的内建类型都不认识
31楼的代码,只要用符合标准的编译器,无论是C,还是C++,都能编译通过,我已经试过了
C++用 VC2008 试过,也用 g++4.7.2 试过
C用 gcc4.72 试过

如果你用的是古老的VC,可以将 long long 改为 __int64,printf中格式化字符串中的ll改为I64就行了
2012-11-15 10:47
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 33楼 rjsp
是这个意思,我做的是行与行之间需要首尾相接的,把所有字符归为一行进行统计。我把1.8G文件(17亿字符)分成了20份,分别输出结果,然后把数据相加。总结果和对1.8G文件整体扫描得出的结果一样。所以我觉得其实不用改数据类型了吧?
2012-11-15 11:41
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 33楼 rjsp
大兄弟啊,我这有个perl的程序,比较简单,不知道你会不会,你看一下。
#!/usr/bin/perl
use strict;
use warnings;
open IN,"1.txt";
open OUT,">2.txt";
 my $dna  = <IN>;
my $revcom = $dna;
$revcom =~ tr /acgt/ACGT/;
my $gc = $revcom =~ tr/GC//;
my $gc_content = sprintf( "%.2F", $gc / length($revcom) * 100 );
my $at = $revcom =~ tr/AT//;
my $at_content = sprintf( "%.2F", $at / length($revcom) * 100 );
my $ALL = $revcom =~ tr/ACGT//;
my $A = $revcom =~ tr/A//;
my $C = $revcom =~ tr/C//;
my $G = $revcom =~ tr/G//;
my $T = $revcom =~ tr/T//;
print OUT "GC数量:$gc\n";
print  OUT "GC含量:${gc_content}%\n";
print OUT "AT数量:$at\n";
print  OUT "AT含量:${at_content}%\n";
print OUT "A总数: $A\n";
print OUT "C总数: $C\n";
print OUT "G总数: $G\n";
print OUT "T总数: $T\n";
print OUT "ACGT总数: $ALL\n";
close OUT;
close IN;
这个程序的问题,是我的数据在18亿个字符,提示信息是是超出内存(out of memmery).这个怎么修改一下啊
2012-11-27 10:16
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 33楼 rjsp
兄弟,先前我是统计8个字符,这个程序很好使,我要是统计四个字符的话,把你这个程序哪个地方改一下就行了?
2013-01-12 20:38



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-386526-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.060362 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved