Code problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Eric Sosman

    #16
    Re: Code problem

    jacob navia wrote:
    [...]
    But the abstract problem is still not clear to me. I mean when I see
    a number like
    >
    -3
    >
    unadorned this is a signed integer constant. Since I am assigning it to
    an unsigned value, I reinterpret the bits as an unsigned (this is my
    mistake probably) and then convert THAT into an unsigned long long.
    Yes, that's the error. Conversion from one type to another
    involves the *value* being converted, not its representation.
    As a related example consider

    signed char sc = -1;
    int a = sc;
    unsigned int b = sc;

    In neither case will "reinterpre t the bits and then convert"
    produce the correct answer. What you're doing is more akin to

    unsigned int c = (unsigned char)sc;

    --
    Eric Sosman
    esosman@ieee-dot-org.invalid

    Comment

    • Jack Klein

      #17
      Re: Code problem

      On Thu, 06 Dec 2007 23:09:24 +0100, jacob navia <jacob@nospam.c om>
      wrote in comp.lang.c:
      I posted this to comp.std.c, but may be of interest here too:
      >
      Consider this:
      >
      extern void abort(void);
      int main (void)
      {
      unsigned long long xx;
      unsigned long long *x = (unsigned long long *) &xx;
      >
      *x = -3;
      *x = *x * *x;
      if (*x != 9)
      abort ();
      return(0);
      }
      >
      lcc-win interprets
      *x = -3;
      as
      *x = 4294967293;
      since x points to an UNSIGNED long long.
      I cast the 32 bit integer -3 into an unsigned integer
      then I cast the result to an unsigned long long.
      >
      Apparently gcc disagrees.
      >
      Am I doing something wrong somewhere?
      Yes, I believe you are.

      The C standard's wording on initializing scalars (6.7.8 P11) states:

      "The initializer for a scalar shall be a single expression, optionally
      enclosed in braces. The initial value of the object is that of the
      expression (after conversion); the same type constraints and
      conversions as for simple assignment apply, taking the type of the
      scalar to be the unqualified version of its declared type."

      Referring to "Simple assignment" 6.5.26.2 P2:

      "In simple assignment (=), the value of the right operand is converted
      to the type of the assignment expression and replaces the value stored
      in the object designated by the left operand."

      Putting these together, the integer constant expression -3, of type
      int, is converted to type unsigned long long. There are no
      intermediate conversions specified or implied to unsigned int or
      signed long long. Your compiler might take these intermediate steps,
      under the as-if rule, but only if you produce the same results as a
      direct conversion.

      And the correct result is (ULLONG_MAX + 1) - 3;
      I should first cast into a long long THEN into an unsigned
      long long?
      No, I think not. What would the result be if you had written either
      of these:

      *x = -3ULL;

      ....or:

      *x = (unsigned long long)3;

      I think you are getting hung up on the details of how you code the
      conversion in your compiler, and losing sight of the meaning of the
      expression in the language.

      The conversion, like all such in C, is defined in terms of value, not
      of steps or types to achieve it.

      As a practical matter, I suspect the simplest method to get the
      correct result would be to convert the signed int constant to signed
      long long, then to unsigned long long.

      Note the following program, and its output when run in VS 2005
      Express, which does not support much of C99 but does support the long
      long types:

      #include <stdlib.h>
      #include <stdio.h>

      int main(void)
      {
      unsigned long long x = (unsigned int)-3;
      unsigned long long y = (unsigned long long)-3;
      unsigned long long z = -3;
      unsigned long long a = (long long)-3;
      printf("x = %llu\ny = %llu\nz = %llu\na = %llu\n",
      x, y, z, a);
      return 0;
      }

      Output:

      x = 4294967293
      y = 184467440737095 51613
      z = 184467440737095 51613
      a = 184467440737095 51613

      So I suspect your compiler will generate the proper value using the
      signed int to signed long long to unsigned long long series of
      conversions.
      Thanks for your help.
      You're welcome.

      --
      Jack Klein
      Home: http://JK-Technology.Com
      FAQs for
      comp.lang.c http://c-faq.com/
      comp.lang.c++ http://www.parashift.com/c++-faq-lite/
      alt.comp.lang.l earn.c-c++

      Comment

      • somenath

        #18
        Re: Code problem

        On Dec 7, 4:02 am, Ben Pfaff <b...@cs.stanfo rd.eduwrote:
        Richard Heathfield <r...@see.sig.i nvalidwrites:
        jacob navia said:
        unsigned long long xx;
        unsigned long long *x = (unsigned long long *) &xx;
        *x = -3;
        *x = *x * *x;
        if (*x != 9)
        abort ();
        >
        It is deeply unlikely that *x will be 9 at this point.
        >
        2**64 - 3 == 184467440737095 51613
        (18446744073709 551613)**2 = 340282366920938 463352694142989 510901769
        340282366920938 463352694142989 510901769 % 2**64 = 9
        >
        At least according to the calculator I have here.

        I beg your pardon for asking basic question in the flow of high level
        technical discussion .I am sorry if it break the flow of the
        discussion .

        My doubt is about the following lines and the result.

        1) *x = -3;
        2) *x = *x * *x;

        After executing line 1) *x will be equal to at least
        184467440737095 51613.
        And after executing line 2)
        *x is 3. But my doubt is how it is possible?

        My doubt is while executing *x * *x is *x again converted to 3 ?
        That's why 3 * 3 is 9? If yes why it is required?
        Because now *x is not negative so it is not required to be converted
        to unsigned.






        Comment

        • James Kuyper

          #19
          Re: Code problem

          somenath wrote:
          On Dec 7, 4:02 am, Ben Pfaff <b...@cs.stanfo rd.eduwrote:
          >Richard Heathfield <r...@see.sig.i nvalidwrites:
          >>jacob navia said:
          >>> unsigned long long xx;
          >>> unsigned long long *x = (unsigned long long *) &xx;
          >>> *x = -3;
          >>> *x = *x * *x;
          >>> if (*x != 9)
          >>> abort ();
          >>It is deeply unlikely that *x will be 9 at this point.
          Actually, it's guaranteed to be 9.
          >2**64 - 3 == 184467440737095 51613
          >(1844674407370 9551613)**2 = 340282366920938 463352694142989 510901769
          >34028236692093 846335269414298 9510901769 % 2**64 = 9
          >>
          >At least according to the calculator I have here.
          >
          >
          I beg your pardon for asking basic question in the flow of high level
          technical discussion .I am sorry if it break the flow of the
          discussion .
          >
          My doubt is about the following lines and the result.
          >
          1) *x = -3;
          2) *x = *x * *x;
          >
          After executing line 1) *x will be equal to at least
          184467440737095 51613.
          And after executing line 2)
          *x is 3. But my doubt is how it is possible?
          *x isn't 3 at that point. It should be 9.
          My doubt is while executing *x * *x is *x again converted to 3 ?
          That's why 3 * 3 is 9? If yes why it is required?
          No. It's a little more interesting than that. All of the following
          expressions are intended to be interpreted mathematically, rather than
          as C expressions that could (and would) overflow. The value that should
          be stored in *x in step 1 is obtained by adding ULLONG_MAX + 1 to -3 as
          many times as are needed to generate a value between 0 an ULLONG_MAX,
          inclusive. In this case, it only has to be added one time:

          ULLONG_MAX + 1 - 3

          Now, let's calculate the mathematical value of the square of that value:

          (ULLONG_MAX + 1)^2 -2*3*(ULLONG_MAX + 1) + 9

          = (ULLONG_MAX - 5)*(ULLONG_MAX + 1) + 9

          The value that is actually stored in *x by step 2 is obtained from that
          mathematical value by (conceptually) subtracting ULLONG_MAX + 1 as many
          times as needed until the result is between 0 and ULLONG_MAX, inclusive.
          I hope it's clear that it needs to be subtracted exactly ULLONG_MAX-5
          times, giving a result of 9. This isn't a coincidence, but a normal
          consequence of modulus arithmetic. In reality, of course, no
          subtractions are actually carried out; the required result is obtained
          naturally as a result of properly implemented unsigned multiplication.
          The explanation given above can be generalized to prove that

          ((a mod c) * (b mod c)) mod c = (a*b) mod c

          (I hope I got the modulus notation right - it's been nearly three
          decades since I last used it)
          In this case, a and b are -3, and c is ULLONG_MAX + 1

          Comment

          • Richard Heathfield

            #20
            Re: Code problem

            James Kuyper said:
            >>Richard Heathfield <r...@see.sig.i nvalidwrites:
            >>>It is deeply unlikely that *x will be 9 at this point.
            >
            Actually, it's guaranteed to be 9.
            I was in error to leave that sentence in my article after discovering that
            it was incorrect. (I wrote an entire paragraph proving that it would not
            be 9, but I ended up proving otherwise, so I deleted the paragraph
            completely, but the above sentence survived, alas.)

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

            Comment

            Working...