What are the minimum and maximum float numbers and integers?

Discussion in 'Perl Misc' started by Peng Yu, Jan 25, 2010.

  1. Peng Yu

    Peng Yu Guest

    Is there a way to get the minimum and maximum float numbers and
    Peng Yu, Jan 25, 2010
    1. Advertisements

  2. perldoc POSIX
    Jochen Lehmeier, Jan 25, 2010
    1. Advertisements

  3. Peng Yu

    Brad Baxter Guest

    use warnings;
    use strict;

    sub min { $_[$_[0]>$_[1]] }
    sub max { $_[$_[0]<$_[1]] }

    my @a = ( 1, 2, 3 );

    my( $max, $min ) = ($a[0])x2;

    for( 1 .. $#a ) {
    $max = max( $max, $a[$_] );
    $min = min( $min, $a[$_] );

    print "Max is: $max\n";
    print "Min is: $min\n";

    But you probably meant something else. :)
    Brad Baxter, Jan 26, 2010
  4. Peng Yu

    sreservoir Guest

    you mean epsilon and, iirc, omega?
    sreservoir, Jan 26, 2010
  5. Peng Yu

    sln Guest

    Something like this should get you in the range.


    use strict;
    use warnings;

    my $exp = 10;
    while (sprintf("%e", 10**$exp) !~ /inf/i) {

    my $places = 6;
    my $mant = 2 - .1; # Because 2 always overflows

    while (sprintf("%e", $mant * 10**$exp) =~ /inf/i) {
    $mant /= 1 + 10**(-$places);

    printf ("UINT: %u\n", -1);
    printf ("INT: +/- %d\n", sprintf ("%u", -1) / 2);
    printf ("FLOAT: +/- %.".$places."e\n", $mant * 10**$exp);


    UINT: 4294967295
    INT: +/- 2147483647
    FLOAT: +/- 1.797693e+308
    sln, Jan 26, 2010
  6. Peng Yu

    ilovelinux Guest

    This didn't work for me; it printed:
    INT: +/- -9223372036854775808
    (platform = CYGWIN_NT-5.1 1.7.1(0.218/5/3))

    Replacing it with:
    printf ("INT: +/- %d\n", sprintf ("%u", -1) / 2 - 1);
    didn't help, surprisingly:
    INT: +/- -9223372036854775808

    But the following did the trick:
    printf ("INT: +/- %d\n", sprintf("%u", -1)>>1);
    INT: +/- 9223372036854775807

    As an aside, the format specification with the embedded $places in the
    format, in
    has a more official counterpart, which was derived from printf(3) and
    also works in C:
    printf ("FLOAT: +/- %.*e\n", $places, $mant * 10**$exp);

    Instead of interpolating "$places", use a * in the format
    specification and add $places as an extra argument to printf.
    ilovelinux, Jan 29, 2010
  7. Peng Yu

    sln Guest

    Scary stuff.
    Is this run under Windows XP-64 or 32?
    Is 64 bit native in the OS? What perl distribution?
    Since this is supposed to be 'unsigned', its not too suprising.
    I don't know why division by 2 should be any different than >>1.
    Funny things can happen like the sign bit is duplicated during arithmatic.
    But thats seems more a consequence for signed types less than the native
    machine word (int) of a typed language like C.

    Well, if shift right 1 (not division by 2) works for you, then you don't
    need the sprintf(), a simple printf ("INT: +/- %d\n", -1>>1 );
    will do.

    What does
    printf "%d", 18446744073709551615;
    printf "%d", 18446744073709551615 / 2;
    return? It should return:
    If not, arithmatic operations would be suspect.

    sln, Jan 30, 2010
  8. Peng Yu

    sln Guest

    Or, to clarify (at least in your case), arithmatic operations
    resulting in or on values outside the range of (+/-) signed int (machine word).
    But Windows-64 will run 32-bit programs with sign emulation. It seems more a
    processor feature though.

    sln, Jan 30, 2010
  9. Because division is always done in floating point arithmetic in Perl.
    So the result of (18446744073709551615/2) should be
    9223372036854775807.5 - but that isn't representable in a 53 bit
    mantissa, so it is rounded to the next representable value which happens
    to be 9223372036854775808 (the next lower representable FP value btw is
    9223372036854774784, so subtracting any value <= 512 doesn't have any

    If int(18446744073709551615/2) gives you 9223372036854775807 you
    probably have compiled perl to use long double arithmetic.
    C doesn't define[1] what happens if you right-shift a negative value.

    But Perl does, at least if don't "use integer":

    | Note that both "<<" and ">>" in Perl are implemented directly using
    | "<<" and ">>" in C. If "use integer" (see "Integer Arithmetic") is in
    | force then signed C integers are used, else unsigned C integers are
    | used.
    (perldoc perlop)

    So (-1 >> 1) uses unsigned integer operations. (unsigned)-1 is
    guaranteed to be the largest unsigned integer, so (-1 >> 1) is half of
    that which is half the largest signed integer (unless there are unused
    bits in the implementation, which C allows, but that's exceedingly


    [1] Although I think it's implementation-defined, not undefined.
    Peter J. Holzer, Jan 30, 2010
  10. Peng Yu

    Dr.Ruud Guest

    ITYM: "(-1) >> 1" is the largest signed integer: 0/1/.
    (a 0-bit, and then as many 1-bits as possible)
    Dr.Ruud, Jan 30, 2010
  11. Unary - binds closer than binary >>, so (-1 >> 1) is the same as
    ((-1) >> 1). So I don't see how that differs from what I wrote.


    Peter J. Holzer, Jan 30, 2010
  12. Ah, I see it now: "half the largest signed integer" should of course
    have read "the largest signed integer". Somehow I duplicated the "half".

    Peter J. Holzer, Jan 30, 2010
  13. Peng Yu

    sln Guest

    Doh, what was I thinking. Of course.

    In C, the value passed to printf using formatter %d must be an integer (signed or not).
    So the result of the division, a float, must be coerced to integer:
    printf ("%d", (int)(18446744073709551615/2) );
    Does Perl do this coersion in C or does it do its own rounding then chopping via
    custom methods?

    I guess the IEEE 87 standard is 53 bit mantissa so it can't handle a 64 bit
    (-1) u_integer division, but would handle 32 bit u_integers. That explains
    how printf ("%d", 4294967295/2); works, but how can the previous poster's
    64 bit result be -9223372036854775808 which is almost correct?
    If his Perl is using long-double shouldn't this extend the mantissa past 53 bits?

    As an aside, I wonder if Perl is sometimes compiled to take advantage of
    faster SSE-2 64-bit in lieu of precision 80 bit. I know when I compile C++
    I don't enable support for those instructions, and usually select precision
    over speed.

    Also, I thought cpu's do integer arithmetic +-/*


    sln, Jan 30, 2010
  14. Even if there are padding bits, the C Standard defines the unsigned
    right-shift E1 >> E2 as the integral part of E1 / (2**E2). The result
    must be a valid unsigned integer. As a result, padding bits cannot
    change the meaning of a bitshift operation.

    Philip Potter, Jan 30, 2010
  15. Yes but not necessarily a valid signed integer. More specifically

    UINT_MAX / 2 == INT_MAX

    doesn't have to be true. An unsigned int may use more or less bits for
    representing the value than a signed int.
    This isn't about the meaning but about the result. UINT_MAX >> 2 is
    always the same as UINT_MAX / 2, but this is not necessarily the same as

    Peter J. Holzer, Jan 30, 2010
  16. Since perl is written in C, it obviously does it "in C", but how exactly
    the conversion is done I don't know (and I'm currently too lazy to check
    the source). My guess is that it is a simple cast to unsigned int:

    printf "%d\n", 1E100

    prints -1 on my systems which is the same as

    printf("%d\n", (unsigned int)1E100);

    in C. Since this result is arguably wrong I wouldn't rely on it -
    somebody might someday fix it.

    I think I explained that. What wasn't clear about the explanation?
    The gcc manual says about SSE instructions:

    | For the x86-64 compiler, these extensions are enabled by default.

    So, it you are using perl on a 64 bit Linux system, it will (almost
    certainly) use SSE instructions. The speed advantage is probably small -
    interpreter overhead is likely to be much greater than the time actually
    spent in FP arithmetic.
    CPUs do what they are told.

    Peter J. Holzer, Jan 30, 2010
  17. That's a very good point. I guess this is why C provides those constants
    in the first place :)

    Philip Potter, Jan 31, 2010
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.