in reply to Introspection into floats/NV

I've used this:

sub double_to_bin { my $n = shift; my ( $s, $e, $m ) = unpack "a1 a11 a52", unpack "B64", pack "d>", $n; $e = oct( "0b$e" ); if ( $e == 0x7FF ) { if ( $m =~ /^0+\z/ ) { return $s ? "-inf" : "+inf" ; } else { return "nan"; } } my $n_bin = ( $e ? "1" : "" ) . $m; $e -= 1023; if ( $e < 0 ) { $n_bin = "0." . ( "0" x ( -$e - 1 ) ) . $n_bin; } else { my $z = ( $e + 1 ) - length( $n_bin ); if ( $z >= 0 ) { $n_bin .= "0" x $z; } else { substr( $n_bin, $e+1, 0, "." ); } } $n_bin =~ s/^0+(?=[01])//; if ( $n_bin =~ /\./ ) { #$n_bin =~ s/0+\z//; $n_bin =~ s/\.\z//; } $n_bin = ( $s ? "-" : "" ) . $n_bin; return $n_bin; }

Handles subnormals, infinities and NaNs. [Updated to handle the latter two.]


To print the exact value in decimal, you need up to 1074 decimal places (%.1074f) or 751 in scientific notation (%.751g) for IEEE doubles.

$ perl -e'printf "%.751g\n", unpack "d", pack "Q", 1' 4.94065645841246544176568792868221372365059802614324764425585682500675 +507270208751865299836361635992379796564695445717730926656710355939796 +398774796010781878126300713190311404527845817167848982103688718636056 +998730723050006387409153564984387312473397273169615140031715385398074 +126238565591171026658556686768187039560310624931945271591492455329305 +456544401127480129709999541931989409080416563324524757147869014726780 +159355238611550134803526493472019379026810710749170333222684475333572 +083243193609238289345836806010601150616980975307834227731832924790498 +252473077637592724787465608477820373446969953364701797267771758512566 +055119913150489110145103786273816725095583738973359899366480994116420 +5702637090279242767544565229087538682506419718265533447265625e-324

Replies are listed 'Best First'.
Re^2: Introspection into floats/NV
by syphilis (Archbishop) on Jun 03, 2025 at 22:33 UTC
Re^2: Introspection into floats/NV
by LanX (Saint) on Jun 03, 2025 at 16:17 UTC
    Thanks, the second unpack is a good workaround! :)

    printf "%a" should hopefully handle all edge cases.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

      I wrote this before %a was introduced. But %a produces scientific notation, whereas the above doesn't.

        > But %a produces scientific notation, whereas the above doesn't.

        my issue with %a is rather that it's called "hex float" but the exponent is decimal ... LOL.

        I'm happy that it exists anyway, since different builds can have other floats configured, plattforms have various endianness too.

        Furthermore it's a valid number format in Perl.

        DB<18> say 0x1p+10 - 1 1023

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery