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
    integers?
     
    Peng Yu, Jan 25, 2010
    #1
    1. Advertisements

  2. perldoc POSIX
     
    Jochen Lehmeier, Jan 25, 2010
    #2
    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
    #3
  4. Peng Yu

    sreservoir Guest

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

    sln Guest

    Something like this should get you in the range.

    -sln

    ---------------
    use strict;
    use warnings;

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

    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);

    __END__

    UINT: 4294967295
    INT: +/- 2147483647
    FLOAT: +/- 1.797693e+308
     
    sln, Jan 26, 2010
    #5
  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
    #6
  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:
    -1
    9223372036854775807
    If not, arithmatic operations would be suspect.
    ^^
    Thanks.

    -sln
     
    sln, Jan 30, 2010
    #7
  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
     
    sln, Jan 30, 2010
    #8
  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
    effect).

    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
    rare).

    hp

    [1] Although I think it's implementation-defined, not undefined.
     
    Peter J. Holzer, Jan 30, 2010
    #9
  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
    #10
  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.

    Yes.

    hp
     
    Peter J. Holzer, Jan 30, 2010
    #11
  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".

    hp
     
    Peter J. Holzer, Jan 30, 2010
    #12
  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 +-/*

    Thanks.

    -sln
     
    sln, Jan 30, 2010
    #13
  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.

    Phil
     
    Philip Potter, Jan 30, 2010
    #14
  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
    INT_MAX.

    hp
     
    Peter J. Holzer, Jan 30, 2010
    #15
  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.

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

    Phil
     
    Philip Potter, Jan 31, 2010
    #17
    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.