Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

portably finding max integer

by martin (Friar)
on May 24, 2009 at 16:46 UTC ( [id://765935]=perlquestion: print w/replies, xml ) Need Help??

martin has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I am designing a library module that should be able to switch from native perl integer arithmetic to Math::BigInt if need arises. To that end I need to find out the biggest integer of the currently running perl interpreter in a portable way. For now I have come up with two approaches:
# solution 1 use Config; if ($Config{'use64bitint'}) { # max_integer is probably 2**63-1 } else { # max_integer is probably 2**31-1 }
# solution 2 my $max_int = (-1)>>1;
Both solutions seem to work on UNIX/i386 machines I have access to. But how portable is either one? Is there a better way? In case of doubt my module should rather assume a smaller value than risk loss of precision when perl internally switches to floating point. Would 2147483647 (2**31-1) be an integer value for any perl (5.6 or higher) on any platform out there?

Replies are listed 'Best First'.
Re: portably finding max integer
by shmem (Chancellor) on May 24, 2009 at 18:02 UTC

    The following seems to be accurate

    $max_unsigned_int = ~0; $max_signed_int = -1 >> 1;

    according to perlop:

    Unary "~" performs bitwise negation, i.e., 1’s complement. For example, "0666 & ~027" is 0640. (See also "Integer Arithmetic" and "Bitwise String Operators".) Note that the width of the result is platform-dependent: ~0 is 32 bits wide on a 32-bit platform, but 64 bits wide on a 64-bit platform, so if you are expecting a certain bit width, remember to use the & operator to mask off the excess bits.
Re: portably finding max integer
by BrowserUk (Patriarch) on May 24, 2009 at 20:57 UTC

    It would be a premature pessimisation to move to using Math::BigInt on a 32-bit integer machine until you've exploited the ability of doubles to hold 53-bit integers accurately. That would make the breakpoint: 9007199254740992.

    If there is any chance of a version of perl using something other than a 64-bit double, then you can determine the break point dynamically using:

    my $n = 2; $n *=2 until $n+0.5 == $n; $n *=2; print $n;

    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".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Many thanks for the responses. It turns out there is more to consider about doing precise integer arithmetic in Perl than what I originally asked.

      The perlop documentation shmem brought to my attention gives a formula for a big integer value but also mentions that most arithmetic is carried out in floating-point by default. The integer pragma can change that but will also have consequences for signed/unsigned, division and modulus semantics.

      jwkrahn demonstrated that the POSIX module provides an own set of various numerical limits. I guess, however, that those apply to this particular interface rather than to perl internals.

      Finally, BrowserUk suggested exploiting floating-point precision on 32-bit machines and gave a code snippet probing for the precision actually available.

      One question that has not been answered yet is whether 31 bit for positive values was as bad as it can get. I have found no counter-examples so far.

      In short, there are more factors determining whether an arithmetic result can be expected to be precise than a simple size check. I'll have to look more closely into automatic numerical type conversion and how perl handles individual operators.

      For example, on a machine with less precision in floats than in integers (a 64-bit machine with IEEE doubles, say), downgrading integer to floating-point should be avoided just like downgrading fp to 32-bit integer on other machines.

      But this may be hard to accomplish if the underlying model suggests that integers are considered a subset of floats. I have already found a perl that will do bit-operations in 64-bit unsigned integer but numerical comparison in 53-bit signed floating-point or something, which means that you can have numerically equal values that are different bit-wise (example: 1<<60|1 versus 1<<60).

      I'll post a meditation with my findings when I'm done.

        Yes, Perl guarantees that IV will be at least 32 bits. And you will have better luck building your Perl so that NVs have more mantissa bits than IVs (if you have 64-bit IV, then use 'long double' for NV) as making allowances for IV being better for some values and NV being better for other values is quite complicated (doomed to fail in some cases, I say) and has also only been introduced to Perl fairly recently.

        - tye        

Re: portably finding max integer
by jwkrahn (Abbot) on May 24, 2009 at 18:34 UTC
    $ perl -MPOSIX -le'print for CHAR_MAX, INT_MAX, LONG_MAX, SHRT_MAX, UC +HAR_MAX, UINT_MAX, ULONG_MAX, USHRT_MAX' 127 2147483647 2147483647 32767 255 4294967295 4294967295 65535

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://765935]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (5)
As of 2024-03-19 02:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found