C99 complex numbers and aliasing

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Glen Low

    C99 complex numbers and aliasing

    Suppose I have a complex number as follows:

    double _Complex d;

    Can I access the real part as

    ((double*) d) [0]

    and the imaginary part as

    ((double*) d) [1] ?

    The C99 seems to say yes in 6.25/13 which specifies the layout of
    complex numbers, and possibly no in 6.5/7 which may rule out double
    _Complex and double aliasing?

    I'm trying to find a portable way of using gcc's __real__ and __imag__
    extensions, which work as lvalues.

    Cheers,
    Glen Low, Pixelglow Software

  • Kevin Bracey

    #2
    Re: C99 complex numbers and aliasing

    In message <9215d7ac.04080 30535.f55c34f@p osting.google.c om>
    glenlow@pixelgl ow.com (Glen Low) wrote:
    [color=blue]
    > Suppose I have a complex number as follows:
    >
    > double _Complex d;
    >
    > Can I access the real part as
    >
    > ((double*) d) [0]
    >
    > and the imaginary part as
    >
    > ((double*) d) [1] ?
    >
    > The C99 seems to say yes in 6.25/13 which specifies the layout of
    > complex numbers, and possibly no in 6.5/7 which may rule out double
    > _Complex and double aliasing?[/color]

    I don't think you're guaranteed to be able to do that portably, because of
    6.5p7. But you can do

    double r, i;
    double _Complex d;

    memcpy(&d, &r, sizeof(double))
    memcpy((double *) &d + 1, &i, sizeof(double))

    I believe. I think that's all the representation alignment actually
    guarantees you by the letter of the standard.

    An alternative thing to do to set just the real part, say, would be:

    d = r + I*cimag(d);

    If an idiom like that becomes standard, it is likely that compilers will spot
    it and optimise it.

    --
    Kevin Bracey, Principal Software Engineer
    Tematic Ltd Tel: +44 (0) 1223 503464
    182-190 Newmarket Road Fax: +44 (0) 1728 727430
    Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/

    Comment

    • James Kuyper

      #3
      Re: C99 complex numbers and aliasing

      glenlow@pixelgl ow.com (Glen Low) wrote in message news:<9215d7ac. 0408030535.f55c 34f@posting.goo gle.com>...[color=blue]
      > Suppose I have a complex number as follows:
      >
      > double _Complex d;
      >
      > Can I access the real part as
      >
      > ((double*) d) [0]
      >
      > and the imaginary part as
      >
      > ((double*) d) [1] ?
      >
      > The C99 seems to say yes in 6.25/13 which specifies the layout of
      > complex numbers, and possibly no in 6.5/7 which may rule out double
      > _Complex and double aliasing?[/color]


      The standard routinely uses "same representation and same alignment"
      with the apparant intent of implying precisely that kind of
      compatibility. However, it falls short of explicitly saying so. As a
      practical matter, I think you can safely assume that "same
      representation and same alignment" means precisely that, whether the
      standard says so explicitly or not. The problem will be resolved
      either by continuing to ignore it, or by adding explicit wording to
      that effect; not by making such code non-portable.

      Comment

      • Mark Piffer

        #4
        Re: C99 complex numbers and aliasing

        Kevin Bracey <kevin.bracey@t ematic.com> wrote in message news:<773834d94 c.kbracey@temat ic.com>...[color=blue]
        > In message <9215d7ac.04080 30535.f55c34f@p osting.google.c om>
        > glenlow@pixelgl ow.com (Glen Low) wrote:
        >[color=green]
        > > Suppose I have a complex number as follows:
        > >
        > > double _Complex d;
        > >
        > > Can I access the real part as
        > >
        > > ((double*) d) [0]
        > >
        > > and the imaginary part as
        > >
        > > ((double*) d) [1] ?[/color]
        >
        > I don't think you're guaranteed to be able to do that portably, because of
        > 6.5p7. But you can do
        >
        > double r, i;
        > double _Complex d;
        >
        > memcpy(&d, &r, sizeof(double))
        > memcpy((double *) &d + 1, &i, sizeof(double))
        >[/color]

        Can you please explain why giving the "(double *) &d + 1" argument is
        any different from the "((double*) d) [1]" access? (No critism meant,
        really just asking). To me 6.5p6 sounds like memcpy too, only works on
        objects without declared type, i.e. you haven't the right to access it
        as a complex afterwards (does this imply that memcpy isn't doing any
        kind of magic behind the curtain which a simple loop could not do?). I
        wonder what I got wrong this time. These questions about
        basic-as-can-be operations really make me wonder everytime if I should
        have avoided usenet in the first place ;)

        regards,
        Mark

        Comment

        • Kevin Bracey

          #5
          Re: C99 complex numbers and aliasing

          In message <cce99527.04082 00750.1bdfffd5@ posting.google. com>
          sorryonly4spam@ yahoo.com (Mark Piffer) wrote:
          [color=blue]
          > Kevin Bracey <kevin.bracey@t ematic.com> wrote in message news:<773834d94 c.kbracey@temat ic.com>...[color=green]
          > > In message <9215d7ac.04080 30535.f55c34f@p osting.google.c om>
          > > glenlow@pixelgl ow.com (Glen Low) wrote:
          > >[color=darkred]
          > > > Suppose I have a complex number as follows:
          > > >
          > > > double _Complex d;
          > > >
          > > > Can I access the real part as
          > > >
          > > > ((double*) d) [0]
          > > >
          > > > and the imaginary part as
          > > >
          > > > ((double*) d) [1] ?[/color]
          > >
          > > I don't think you're guaranteed to be able to do that portably, because of
          > > 6.5p7. But you can do
          > >
          > > double r, i;
          > > double _Complex d;
          > >
          > > memcpy(&d, &r, sizeof(double))
          > > memcpy((double *) &d + 1, &i, sizeof(double))
          > >[/color]
          >
          > Can you please explain why giving the "(double *) &d + 1" argument is
          > any different from the "((double*) d) [1]" access? (No critism meant,
          > really just asking).[/color]

          It's down to aliasing rules. The compiler is free to assume that you don't
          access objects as though they were different types. Thus, in

          double complex cd;
          double *pr = (double *) &cd;

          cd = 2 + I;
          *pr = 3;

          The compiler is allowed to assume after this that cd still contains 2+I, as
          it "knows" that a write to a double cannot alter an object of type complex
          double. Paragraph 6.5p7 basically says that.

          Now, those rules were originally designed to handle more clear-cut cases,
          like writing to a float through an int * pointer. It's arguable that an
          exception should be added to the list saying that the parts of a complex or
          imaginary object can be accessed as its corresponding real type.

          memcpy accesses objects as characters, thus is permitted by the last line of
          6.5p7.

          --
          Kevin Bracey, Principal Software Engineer
          Tematic Ltd Tel: +44 (0) 1223 503464
          182-190 Newmarket Road Fax: +44 (0) 1728 727430
          Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/

          Comment

          • David R Tribble

            #6
            Re: C99 complex numbers and aliasing

            Glen Low wrote:[color=blue][color=green]
            >> Can I access the real part as
            >> ((double*) d) [0]
            >> and the imaginary part as
            >> ((double*) d) [1] ?[/color][/color]

            Mark Piffer wrote:[color=blue]
            > Can you please explain why giving the "(double *) &d + 1" argument is
            > any different from the "((double*) d) [1]" access? (No critism meant,
            > really just asking).[/color]


            These are equivalent:
            ((double *)&d)[1]
            *((double *)&d + 1)

            The original post is missing an '&', since 'd' is a complex double and
            not a pointer.

            -drt

            Comment

            Working...