在 bash/perl 中将科学记数法转换为十进制(不是整数)
Posted
技术标签:
【中文标题】在 bash/perl 中将科学记数法转换为十进制(不是整数)【英文标题】:convert scientific notation to decimal (not integer) in bash/perl 【发布时间】:2014-04-10 01:01:29 【问题描述】:我有一个制表符分隔的文件,其中包含几列(9 列),如下所示:
1:21468 1 21468 2.8628817609765984 0.09640845515631684 0.05034710996552612 1.0 0.012377712911711025 54.0
但是,在第 5 列中,我有时会有如下科学数字:
8.159959468796783E-4
8.465114165595303E-4
8.703354859736187E-5
9.05132870067004E-4
我需要将第 5 列中的所有数字都以十进制表示。从上面的例子:
0.0008159959468796783
0.0008465114165595303
0.00008703354859736187
0.000905132870067004
我需要更改这些数字,而不更改第 5 列中的其余数字或文件的其余部分。
我知道Convert scientific notation to decimal in multiple fields 中有类似的帖子。但在这种情况下,有一个与字段中存在的数字类型无关的 if 语句,它适用于该列中的所有数字。因此,我无法将其中的信息转换为我的具体案例。有人可以帮我解决这个问题吗?
谢谢!
【问题讨论】:
【参考方案1】:将 perl 中的科学记数法数字转换为常规记数法数字的最简单(也是最快)的方法:
my $num = '0.12345678E5';
$num *= 1;
print "$num\n";
【讨论】:
【参考方案2】:正如 Jim 已经提出的,一种方法是简单地将数字视为字符串并自己进行翻译。这样您就可以完全保持您的有效数字。
以下演示了一个用于执行此操作的函数。它接受一个可能是科学计数法的数字,并返回十进制表示。适用于正指数和负指数:
use warnings;
use strict;
while (<DATA>)
my ($num, $expected) = split;
my $dec = sn_to_dec($num);
print $dec . ' - ' . ($dec eq $expected ? 'good' : 'bad') . "\n";
sub sn_to_dec
my $num = shift;
if ($num =~ /^([+-]?)(\d*)(\.?)(\d*)[Ee]([-+]?\d+)$/)
my ($sign, $int, $period, $dec, $exp) = ($1, $2, $3, $4, $5);
if ($exp < 0)
my $len = 1 - $exp;
$int = ('0' x ($len - length $int)) . $int if $len > length $int;
substr $int, $exp, 0, '.';
return $sign.$int.$dec;
elsif ($exp > 0)
$dec .= '0' x ($exp - length $dec) if $exp > length $dec;
substr $dec, $exp, 0, '.' if $exp < length $dec;
return $sign.$int.$dec;
else
return $sign.$int.$period.$dec;
return $num;
__DATA__
8.159959468796783E-4 0.0008159959468796783
8.465114165595303E-4 0.0008465114165595303
8.703354859736187E-5 0.00008703354859736187
9.05132870067004E-4 0.000905132870067004
9.05132870067004E+4 90513.2870067004
9.05132870067004E+16 90513287006700400
9.05132870067004E+0 9.05132870067004
【讨论】:
【参考方案3】:如果您以简单的方式执行此操作,即解析为浮点数,然后使用 printf 强制将其打印为小数,您最终可能会得到略有不同的结果,因为您处于双精度的上限-精度格式。
你应该做的是将每一行分成多个字段,然后用类似这样的方式检查字段 5。
($u,$d,$exp) = $field[5] =~ /(\d)\.(\d+)[Ee]([-+]\d+)/
如果字段[5] 是科学记数法,这会给你
$u the digit before the decimal
$d the digits after the decimal
$exp the exponent
(如果不是,您将返回未定义的值,并且可以跳过重新格式化步骤)
使用该信息,您可以使用正确数量的前导零和小数点重新组合数字。如果指数是正数,则必须重新组合数字,然后在正确的位置插入小数点。
按照您想要的方式重新格式化值后,重新组合整行(例如,使用join
)并将其写出。
【讨论】:
以上是关于在 bash/perl 中将科学记数法转换为十进制(不是整数)的主要内容,如果未能解决你的问题,请参考以下文章