in reply to Re^4: Determining the minimum representable increment/decrement possible?
in thread Determining the minimum representable increment/decrement possible?

I was asked off-line to explain what I meant by:

he uses convoluted and complicated numerical methods rather than simple and pragmatic bitwise methods

Which would you rather maintain or debug? My routine for formating a double into a hexadecimal floating point constant:

use constant { SIGNBIT => 0x8000_0000_0000_0000, EXPBITS => 0x7FF0_0000_0000_0000, SIGBITS => 0xF_FFFF_FFFF_FFFF, INDBITS => 0x8_0000_0000_0000, }; sub asHex{ my $bin = unpack 'Q', pack 'd', $_[X]; return "-0x1.#IND000000000p+0" if $bin == NEG_IND; my $sign = ( $bin & SIGNBIT ) ? '-' : ' '; my $exp = ( ( $bin & EXPBITS ) >> 52 ); my $mant = $bin & SIGBITS; if( $exp == 2047 ) { return $sign . "0x1.#INF000000000p+0" unless $mant; return $sign . ( $mant < INDBITS ? "0x1.#SNAN00000000p+0" : "0 +x1.#QNAN00000000p+0" ); } $exp -= 1023; my $hid = $exp == -1023 ? ( ++$exp, 0 ) : 1; sprintf "%s0x%1u.%013xp%+d", $sign, $hid, $mant, $exp; }

Or same thing from Data::Float:

my %float_hex_defaults = ( infinite_string => "inf", nan_string => "nan", exp_neg_sign => "-", exp_pos_sign => "+", pos_sign => "+", neg_sign => "-", hex_prefix_string => "0x", subnormal_strategy => "SUBNORMAL", zero_strategy => "STRING=0.0", frac_digits => 0, frac_digits_bits_mod => "ATLEAST", frac_digits_value_mod => "ATLEAST", exp_digits => 0, exp_digits_range_mod => "IGNORE", ); sub _float_hex_option($$) { my($options, $name) = @_; my $val = defined($options) ? $options->{$name} : undef; return defined($val) ? $val : $float_hex_defaults{$name}; } use constant exp_digits_range => do { my $minexp = min_normal_exp - significand_bits; my $maxexp = max_finite_exp + 1; my $len_minexp = length(-$minexp); my $len_maxexp = length($maxexp); $len_minexp > $len_maxexp ? $len_minexp : $len_maxexp; }; use constant frac_digits_bits => (significand_bits + 3) >> 2; use constant frac_sections => do { use integer; (frac_digits_bits + 6) + / 7; }; sub float_hex($;$) { my($val, $options) = @_; return _float_hex_option($options, "nan_string") if $val != $val; if(have_infinite) { my $inf_sign; if($val == $pos_infinity) { $inf_sign = _float_hex_option($options, "pos_sign"); EMIT_INFINITY: return $inf_sign. _float_hex_option($options, "infinite_string"); } elsif($val == $neg_infinity) { $inf_sign = _float_hex_option($options, "neg_sign"); goto EMIT_INFINITY; } } my($sign, $exp, $sgnf); if($val == 0.0) { $sign = float_sign($val); my $strat = _float_hex_option($options, "zero_strategy"); if($strat =~ /\ASTRING=(.*)\z/s) { my $string = $1; return _float_hex_option($options, $sign eq "-" ? "neg_sign" : "pos_sign"). $string; } elsif($strat eq "SUBNORMAL") { $exp = min_normal_exp; } elsif($strat =~ /\AEXPONENT=([-+]?[0-9]+)\z/) { $exp = $1; } else { croak "unrecognised zero strategy `$strat'"; } $sgnf = 0.0; } else { ($sign, $exp, $sgnf) = float_parts($val); } my $digits = int($sgnf); if($digits eq "0" && $sgnf != 0.0) { my $strat = _float_hex_option($options, "subnormal_strategy"); if($strat eq "NORMAL") { my $add_exp; (undef, $add_exp, $sgnf) = float_parts($sgnf); $exp += $add_exp; $digits = "1"; } elsif($strat eq "SUBNORMAL") { # do nothing extra } else { croak "unrecognised subnormal strategy `$strat'"; } } $sgnf -= $digits; for(my $i = frac_sections; $i--; ) { $sgnf *= 268435456.0; my $section = int($sgnf); $digits .= sprintf("%07x", $section); $sgnf -= $section; } $digits =~ s/(.)0+\z/$1/; my $ndigits = 1 + _float_hex_option($options, "frac_digits"); croak "negative number of digits requested" if $ndigits <= 0; my $mindigits = 1; my $maxdigits = $ndigits + frac_digits_bits; foreach my $constraint (["frac_digits_bits_mod", 1+frac_digits_bit +s], ["frac_digits_value_mod", length($digits)]) { my($optname, $number) = @$constraint; my $mod = _float_hex_option($options, $optname); if($mod =~ /\A(?:ATLEAST|EXACTLY)\z/) { $mindigits = $number if $mindigits < $number; } if($mod =~ /\A(?:ATMOST|EXACTLY)\z/) { $maxdigits = $number if $maxdigits > $number; } croak "unrecognised length modification setting `$mod'" unless $mod =~ /\A(?:AT(?:MO|LEA)ST|EXACTLY|IGNORE)\z/; } croak "incompatible length constraints" if $maxdigits < $mindigits +; $ndigits = $ndigits < $mindigits ? $mindigits : $ndigits > $maxdigits ? $maxdigits : $ndigits; if($ndigits > length($digits)) { $digits .= "0" x ($ndigits - length($digits)); } elsif($ndigits < length($digits)) { my $chopped = substr($digits, $ndigits, length($digits), ""); if($chopped =~ /\A[89abcdef]/ && !($chopped =~ /\A80*\z/ && $digits =~ /[02468ace]\z/)) { for(my $i = length($digits) - 1; ; ) { my $d = substr($digits, $i, 1); $d =~ tr/0-9a-f/1-9a-f0/; substr($digits, $i, 1, $d); last unless $d eq "0"; } if($digits =~ /\A2/) { $exp++; substr($digits, 0, 1, "1"); } } } my $nexpdigits = _float_hex_option($options, "exp_digits"); my $mod = _float_hex_option($options, "exp_digits_range_mod"); if($mod eq "ATLEAST") { $nexpdigits = exp_digits_range if $nexpdigits < exp_digits_range; } elsif($mod ne "IGNORE") { croak "unrecognised exponent length ". "modification setting `$mod'"; } $digits =~ s/\A(.)(.)/$1.$2/; return sprintf("%s%s%sp%s%0*d", _float_hex_option($options, $sign eq "-" ? "neg_sign" : "pos_sign"), _float_hex_option($options, "hex_prefix_string"), $digits, _float_hex_option($options, $exp < 0 ? "exp_neg_sign" : "exp_pos_sign"), $nexpdigits, abs($exp)); }

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
In the absence of evidence, opinion is indistinguishable from prejudice. Not understood.