perl 从四进制快速切换到十进制
Posted
技术标签:
【中文标题】perl 从四进制快速切换到十进制【英文标题】:perl quick switch from quaternary to decimal 【发布时间】:2012-09-20 20:30:17 【问题描述】:我将核苷酸 A、C、G、T 表示为 0、1、2、3,然后我需要将表示为四进制的序列转换为十进制。有没有办法在 perl 中实现这一点?我不确定打包/解包是否可以做到这一点。
【问题讨论】:
请更清楚地描述您想要什么,并向我们展示您的尝试! 所以你想要来自3031
的205
?
您是否计划输入长度超过 8 位?
所以,对于DNA序列,比如“ACGTTTCGA”,我要像$dna =~ tr/ACGT/0123/这样转换,转换后的序列是一串数字,但是每个数字只能是0-3,不像十进制可以是0-9。我想把这串数字转换成十进制整数。这就像二进制和十进制之间的关系。就这么简单
想问你为什么要这样做?
【参考方案1】:
Base 4 正好需要 2 位,因此很容易高效处理。
my $uvsize = length(pack('J>', 0)) * 8;
my %base4to2 = map $_ => sprintf('%2b', $_) 0..3;
sub base4to10
my ($s) = @_;
$s =~ s/(.)/$base4to2$1/sg;
$s = substr(("0" x $uvsize) . $s, -$uvsize);
return unpack('J>', pack('B*', $s));
这允许在支持 32 位整数的版本上输入 16 位数字,在支持 64 位整数的版本上允许输入 32 位数字。
使用浮点数支持稍大的数字是可能的:使用 IEEE 双精度数的构建为 26,使用 IEEE 四元数的构建为 56。这将需要不同的实现。
如果比这更大,则需要一个诸如 Math::BigInt 之类的模块,以便 Perl 存储它们。
更快更简单:
my %base4to16 = (
'0' => '0', '00' => '0', '20' => '8',
'1' => '1', '01' => '1', '21' => '9',
'2' => '2', '02' => '2', '22' => 'A',
'3' => '3', '03' => '3', '23' => 'B',
'10' => '4', '30' => 'C',
'11' => '5', '31' => 'D',
'12' => '6', '32' => 'E',
'13' => '7', '33' => 'F',
);
sub base4to10
(my $s = $_[0]) =~ s/(..?)/$base4to16$1/sg;
return hex($s);
【讨论】:
注意:此解决方案会丢失有关存在多少前导零的信息(但 OP 说没关系)。 添加了更快更简单的解决方案。 看来函数 hex($s) 不能处理大于 16 的长度,对吧? @lolibility,hex
无法处理超出您的 Perl 支持的数字,我的帖子已经详细说明了您的 Perl 可以支持的数字。在我发布答案前一小时,我问你需要处理多大的数字,而你仍然没有回答......请回答。
抱歉,没注意到,我可能要处理由 32 个核苷酸组成的序列。还有我的 perl 和操作系统信息“这是 perl,为 x86_64-linux-thread-multi 构建的 v5.8.8”【参考方案2】:
我从未使用过它,但它看起来像 Convert::BaseN 模块将是一个不错的选择。 Convert::BaseN - encoding and decoding of base2,4,8,16,32,64 strings
【讨论】:
你不太明白我的意思。由于翻译部分很简单,请使用 $mysequence =~ tr/ACGT/0123/ 之类的代码;但翻译后,序列由一串数字表示。但我想将它们转换成一个整数,因为那串数字是四进制的,每个数字只能是 0-3,不像十进制,每个数字可以是 0-9。就像二进制和十进制的关系 打包字符串,但是你必须将它们解包为十进制,所以这只是答案的一半。【参考方案3】:通过处理循环中的每个数字来将base-4字符串计算为十进制非常简单
请注意,在 32 位机器上,您将无法表示长度超过 16 个碱基的序列
这段代码说明了这个想法
use strict;
use warnings;
print seq2dec('ACGTACGTACGTACGT');
sub seq2dec
my ($sequence) = @_;
my $n = 0;
for (map index 'ACGT', $_ split //, $sequence)
$n = $n * 4 + $_;
return $n;
输出
454761243
【讨论】:
如果我的机器是64位的,那么我可以表示一个序列多长时间? 在 64 位平台上,您可以表示 32 个碱基,但您需要安装 64 位 Perl。如果将其保留为字符串,则可以存储不定长度的序列,但也可以将其编码为 ACGT 字符 这里有一个问题,就是没有办法保持原始序列的长度。无论序列中有多少个碱基,AAAAAAAAAA
在十进制中都只是零
这对我来说没关系,我的一个程序运行的所有 DNA 序列都是相同的长度,所以,不用担心 A、AA、AAA 或 A...A 的相同整数表示
我关心的是这个速度,不知道如果我使用循环来做加法和电源是否有效以上是关于perl 从四进制快速切换到十进制的主要内容,如果未能解决你的问题,请参考以下文章