我读了Stack Overflow问题 How do I convert a binary string to a number in Perl? ,了解如何在Perl中将二进制整数转换为十进制或反之。但是我如何为浮动做这个呢?
例如,从5.375
转换为101.011
,反之亦然。
答案 0 :(得分:3)
sub number_to_binary_string {
my $in = shift;
my $sign = $in < 0 and $in = abs $in;
my $out = sprintf "%b.", int $in;
substr $out, 0, 0, '-' if $sign;
$in -= int $in;
do {
if ($in >= .5) {
$out .= '1';
$in -= .5;
}
else {
$out .= '0';
}
$in *= 2;
} while $in > 0;
return $out;
}
sub binary_string_to_number {
my $in = shift;
my ($int,$frac) = split /\./, $in;
my $sign = $int =~ s/^-//;
my $out = oct "0b$int";
my $mult = 1;
for my $digit (split //, $frac) {
$mult *= .5;
$out += $mult * $digit;
}
$out = -$out if $sign;
return $out;
}
答案 1 :(得分:2)
下面是一个特定于机器和构建的实现(NV = little-endian double)。
它返回存储的数字,它支持NaN,Infinity,-Infinity和-0以及subnormals。它修剪前导零和尾随十进制零。
sub double_to_bin {
my ($n) = @_;
my ($s, $e, $m) = unpack 'a a11 a52', unpack 'B64', "".reverse pack 'F', $n;
$s = $s ? '-' : '';
$e = oct("0b$e");
if ($e == 0x7ff) {
return ($m =~ /1/) ? 'NaN' : $s . 'Infinity'
} elsif ($e == 0x000) {
$m = "0$m"; $e -= 52;
} else {
$m = "1$m"; $e -= 1075;
}
if ($e >= 0) {
$m .= ('0' x $e);
} elsif ($e >= -52) {
substr($m, $e+53, 0, '.');
} else {
$m = '0.' . ('0' x (-$e-53)) . $m;
}
$m =~ s/^0+(?!\.)//;
$m =~ s/(?:\..*1\K|\.)0+\z//;
return $s . $m;
}
答案 2 :(得分:1)
这是一个有趣的“便携式”实现的草图。它不处理任何有趣的边缘情况,如整数,NaN,无穷大,甚至是负数,因为我很懒,但扩展它不会那么难。
(my $bin = sprintf "%b.%032b", int($num), 2**32 * ($num - int($num)))
=~ s/\.?0+$//;
2 ** 32看起来像是一个特定于体系结构的魔术数字,但实际上它基本上只是在点之后你需要多少位精度。太小,你得到无害的截断;太大而且有溢出的可能性(因为%b
可能在进行格式化之前的某个时候转换为UV。)
答案 3 :(得分:0)
$TO_BIN = '-b';
$TO_DEC = '-d';
($op, $n ) = @ARGV;
die("USAGE: $0 -b <dec_to_convert> | -d <bin_to_convert>\n") unless ( $op =~ /^($TO_BIN|$TO_DEC)$/ && $n );
for (split(//,$n)) {
if ($_ eq ".") {
$f=".";
} else {
if (defined $f) { $f.=$_ } else { $i.=$_ }
}
}
$ci = sprintf("%b", $i) if $op eq $TO_BIN;
$ci = sprintf("%d", eval "0b$i") if $op eq $TO_DEC;
@f=split(//,$f) if $f;
if ($op eq $TO_BIN) {
while( $f && length($cf) < 16 ) {
($f *= 2) =~ s/(\d)(\.?.*)/$2/;
$cf .= $1 ? '1' : '0';
}
} else {
for ($i=1;$i<@f;$i++) {
$cf = ($cf + $f[@f-$i])/2;
}
}
$cf=~s/^.*\.|^/./ if $cf;
print("$ci$cf\n");