Hi,

I was initially going to mark this post as off-topic ... still not entirely sure whether I should have ....
The question relates specifically to perls for which both $Config{ivsize} and $Config{nvsize} are both 8. That is, perl's integer type (UV/IV) is 64-bit, and perl's floating point type (NV) is either a double or an 8-byte long double.

The aim is to determine whether a given integer value can be represented exactly as a double.
Clearly, any integer <= 9007199254740992 can be represented exactly as a double. (9007199254740992 == 2 ** 53.)
In addition to those values, however, any integer whose highest set bit and lowest set bit are separated by 51 or fewer bits is also exactly representable as a double.

Here follows my solution. The question is "Is there a better way ?".
Assume that the given arg is an integer in the range 0 .. 18446744073709551615 (with 18446744073709551615 being the largest possible UV value).
As an XSub:
int uv_fits_double(UV arg) { if(arg < 9007199254740993) return 1; while(!(arg & 1)) { arg >>= 1; if(arg < 9007199254740993) return 1; } return 0; }
And as perl sub:
sub uv_fits_double { my $arg = shift; return 1 if $arg < 9007199254740993; while(!($arg & 1)) { $arg >>= 1; return 1 if $arg < 9007199254740993; } return 0; }
It annoys me that I can't find a way to detect and shift all of the trailing zero bits off in one hit - and that I instead have to detect and shift them off one at a time.
The number of times that the "$arg < 9007199254740993" comparison is evaluated also annoys me. (Doing that evaluation inside the while loop means that the while loop will perform a maximum of 11 cycles. Without that evaluation it could perform up to 63 cycles.)

As I understand it, the only thing I need to determine is "Are there more than 51 bits between the highest set bit and the lowest set bit ?", and I do that by shifting off all trailing unset bits so that I can then determine (by examining the remaining value) whether it fits into 53 bits or not.
It feels like there ought to be a quicker, simpler way of doing it ... but I don't see one.
A perl demo of the uv_fits_double sub:
use strict; use warnings; use Config; die "This script not meant for this perl configuration" unless $Config{ivsize} == $Config{nvsize}; # The integer value 2251799813685249 is # representable exactly as a double. # Therefore 2251799813685249 * (2 ** 10) # is exactly representable as a double, # since 10 is well within the allowable # exponent range. # 2251799813685249 * (2 ** 10) is also # within the bounds of allowable integer # values. my $fits_d = 2305843009213694976; # 2251799813685249 * (2 ** 10) my $no_fits_d = $fits_d + (2 ** 6); print uv_fits_double(2251799813685249); # fits print uv_fits_double($fits_d); # fits print uv_fits_double($no_fits_d); # doesn't fit print uv_fits_double($fits_d + (2 ** 15)); # fits print "\n"; sub uv_fits_double { my $arg = shift; return 1 if $arg < 9007199254740993; while(!($arg & 1)) { $arg >>= 1; return 1 if $arg < 9007199254740993; } return 0; } __END__ Should output 1101 The 4th value fits, even though it's greater than the 3rd value (which doesn't fit).
Cheers,
Rob

In reply to Detecting whether UV fits into an NV by syphilis

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.