Perl中float到十进制转换的二进制表示

时间:2011-10-05 23:42:19

标签: perl

我读了Stack Overflow问题 How do I convert a binary string to a number in Perl? ,了解如何在Perl中将二进制整数转换为十进制或反之。但是我如何为浮动做这个呢?

例如,从5.375转换为101.011,反之亦然。

4 个答案:

答案 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");