Why does 'uint64_t i = -UINT64_MAX' have value '1'?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Dom Jackson

    Why does 'uint64_t i = -UINT64_MAX' have value '1'?

    What is the value of -(max-val-of-an-unsigned-type)? According to my
    compiler, -UINT32_MAX = 1, and -UINT64_MAX is also 1 (test code
    below).

    From the C99 LRM, p79:

    "The result of the unary - operator is the negative of its (promoted)
    operand. The integer promotions are performed on the operand, and the
    result has the promoted type."

    As far as I can make out from p43, uint32_t and uint64_t are unchanged
    by the integer promotions. So how do you take the negative of an
    unsigned operand, and how can the compiler get the result '1' without
    using a temporary of a higher precision? Any thoughts?

    Thanks -

    Dom

    --------------------------------------------------------------
    [the code below is C++ to simplify data output, and produces this
    result]:

    i is ffffffff; j is 1; k is 1; l is fffffffffffffff f; -l is 1; m is 1

    --------------------------------------------------------------

    #define __STDC_LIMIT_MA CROS
    #include <stdint.h>
    #include <iostream>
    #include <iomanip>

    int main() {
    uint32_t i = UINT32_MAX;
    int64_t j;
    uint64_t k;
    uint64_t l = UINT64_MAX;
    uint64_t m = -UINT64_MAX;

    j = -i;
    k = -i;

    std::cout << std::hex << std::setfill('0 ')
    << "i is " << i
    << "; j is " << j
    << "; k is " << k
    << "; l is " << l
    << "; -l is " << -l
    << "; m is " << m
    << std::endl;

    return 0;
    }


  • Richard Heathfield

    #2
    Re: Why does 'uint64_t i = -UINT64_MAX' have value '1'?

    Dom Jackson said:
    What is the value of -(max-val-of-an-unsigned-type)?
    In C (and presumably in C++ too), arithmetic on unsigned integer types
    is carried out modulo the maximum value of the type + 1. If you try to
    store a negative number in an unsigned integer type, exactly enough
    "maximum value of the type, + 1"s are added to bring it into the range
    representable by the type.

    So let's pretend there's a four-bit unsigned integer type: unsigned
    nibble. :-) UNIBBLE_MAX is 15, so UNIBBLE_MAX + 1 is 16.

    -UNIBBLE_MAX would be -15, so we have to add 16 to that to bring it into
    the representable range, and -15 + 16 is 1.

    Now let's think of an arbitrary unsigned integer type, unsigned arb.
    UARB_MAX has some value or other, doesn't matter what.

    -UARB_MAX is clearly negative, so we need to add enough lots of
    (UARB_MAX + 1) to bring it into the representable range. One is enough,
    so the resulting value is -UARB_MAX + UARB_MAX + 1, which is clearly 1,
    irrespective of the value of UARB_MAX.

    <C++ code snipped>

    When cross-posting between comp.lang.c and comp.lang.c++, please ensure
    that your code snippets are relevant to both groups. Thanks.

    --
    Richard Heathfield <http://www.cpax.org.uk >
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999

    Comment

    • Dom Jackson

      #3
      Re: Why does 'uint64_t i = -UINT64_MAX' have value '1'?

      That's what I call service - thanks!

      On Sat, 23 Jun 2007 18:32:41 +0000, Richard Heathfield
      <rjh@see.sig.in validwrote:
      >So let's pretend there's a four-bit unsigned integer type: unsigned
      >nibble. :-)
      Actually, that's precisely why I needed to know the answer, although
      slightly more generally.
      >-UNIBBLE_MAX would be -15, so we have to add 16 to that to bring it into
      >the representable range, and -15 + 16 is 1.
      Ahhh... I tried this with a 3-bit int, but I was trying to add 8 to
      bit pattern '111', rather than to integer -7, which makes a lot more
      sense.
      >When cross-posting between comp.lang.c and comp.lang.c++, please ensure
      >that your code snippets are relevant to both groups. Thanks.
      I would have, if I'd known of portable printf conversions for 32-bit
      and 64-bit ints - you don't happen to know the answer to that one?

      Thanks -

      Dom

      Comment

      • Richard Heathfield

        #4
        Re: Why does 'uint64_t i = -UINT64_MAX' have value '1'?

        Dom Jackson said:
        That's what I call service - thanks!
        No sweat.

        <snip>
        >>When cross-posting between comp.lang.c and comp.lang.c++, please
        >>ensure that your code snippets are relevant to both groups. Thanks.
        >
        I would have, if I'd known of portable printf conversions for 32-bit
        and 64-bit ints - you don't happen to know the answer to that one?
        C provides two integer types that are guaranteed to be at least 32 bits
        wide: long int, and unsigned long int. The printf function can display
        long int correctly using "%ld", and unsigned long using "%lu". The
        Standard doesn't mandate a maximum size for these types, so they might
        easily be 64 bits wide on some systems, but 32 bits is all you're
        guaranteed.

        C99 (which hardly anyone has a compiler for) introduced two new integer
        types that are guaranteed to be at least 64 bits wide: long long int
        and unsigned long long int. Their printf format specifiers are,
        respectively, "%lld" and "%llu". Don't hold your breath waiting for
        long long and unsigned long long to become portable, though.

        --
        Richard Heathfield <http://www.cpax.org.uk >
        Email: -www. +rjh@
        Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
        "Usenet is a strange place" - dmr 29 July 1999

        Comment

        • Dom Jackson

          #5
          Re: Why does 'uint64_t i = -UINT64_MAX' have value '1'?

          Thanks again -

          Dom

          Comment

          • CBFalconer

            #6
            Re: Why does 'uint64_t i = -UINT64_MAX' have value '1'?

            Dom Jackson wrote:
            Richard Heathfield <rjh@see.sig.in validwrote:
            >
            .... snip ...
            >
            >When cross-posting between comp.lang.c and comp.lang.c++, please
            >ensure that your code snippets are relevant to both groups. Thanks.
            >
            I would have, if I'd known of portable printf conversions for 32-bit
            and 64-bit ints - you don't happen to know the answer to that one?
            printf doesn't do such conversions. The format string tells it the
            actual format of each parameter.

            Follow-ups set to eliminate com.lang.c++. Bad cross-post.

            --
            <http://www.cs.auckland .ac.nz/~pgut001/pubs/vista_cost.txt>
            <http://www.securityfoc us.com/columnists/423>
            <http://www.aaxnet.com/editor/edit043.html>
            cbfalconer at maineline dot net



            --
            Posted via a free Usenet account from http://www.teranews.com

            Comment

            • Rolf Magnus

              #7
              Re: Why does 'uint64_t i = -UINT64_MAX' have value '1'?

              Dom Jackson wrote:
              >>When cross-posting between comp.lang.c and comp.lang.c++, please ensure
              >>that your code snippets are relevant to both groups. Thanks.
              >
              I would have, if I'd known of portable printf conversions for 32-bit
              and 64-bit ints - you don't happen to know the answer to that one?
              There is none for C++. In C(99), you can do:

              #include <stdint.h>
              #include <stdio.h>
              #include <inttypes.h>

              int main()
              {
              int64_t value = 123;
              printf("The value is %" PRId64 "\n", value);
              }

              Comment

              Working...