You are not logged in.

#1 2009-01-28 18:00:58

cmtptr
Member
Registered: 2008-09-01
Posts: 135

[solved] (C) writing floats to struct via pointer argument

Hi,

I hope some expert here can shed some light on this, as it makes no sense to me whatsoever, and I'm really not in the mood to dig through the assembly output to figure out what the compiler is doing different between each case (it wouldn't completely answer my question anyway, as I'd like to know why).

I have written a function which accepts two Quaternion struct pointers.  The function is supposed to perform quaternion multiplication with the two and store the result in the first.  However, transferring the results directly to the first quaternion produces unexpected values which are not correct.  I hope the code can explain the rest.

Here are several relevant typedefs for your reference.

typedef struct
{
    float x;
    float y;
    float z;
} Point3f;

typedef Point3f Vector;

typedef struct
{
    float  s;
    Vector v;
} Quaternion;

And here is the problematic function with comments detailing what I've tried...

void quaternion_mul(Quaternion *dest, const Quaternion *src)
{
    /* THIRD ATTEMPT                                     CORRECT!
     * {1.0, {1.1, 1.2, 1.3}} x {2.0, {2.1, 2.2, 2.3}} = {-5.94, { 4.20,  4.80,  4.80}}
     */
    Quaternion temp;
    temp.s   = (dest->s * src->s) - (dest->v.x * src->v.x) - (dest->v.y * src->v.y) - (dest->v.z * src->v.z);
    temp.v.x = (dest->s * src->v.x) + (dest->v.x * src->s) + (dest->v.y * src->v.z) - (dest->v.z * src->v.y);
    temp.v.y = (dest->s * src->v.y) - (dest->v.x * src->v.z) + (dest->v.y * src->s) + (dest->v.z * src->v.x);
    temp.v.z = (dest->s * src->v.z) + (dest->v.x * src->v.y) - (dest->v.y * src->v.x) + (dest->v.z * src->s);
    *dest = temp;

    /* SECOND ATTEMPT                                    INCORRECT!
     * {1.0, {1.1, 1.2, 1.3}} x {2.0, {2.1, 2.2, 2.3}} = {-5.94, {-10.37,  15.92, -67.32}}
    ((float *)dest)[0] = (dest->s * src->s) - (dest->v.x * src->v.x) - (dest->v.y * src->v.y) - (dest->v.z * src->v.z);
    ((float *)dest)[1] = (dest->s * src->v.x) + (dest->v.x * src->s) + (dest->v.y * src->v.z) - (dest->v.z * src->v.y);
    ((float *)dest)[2] = (dest->s * src->v.y) - (dest->v.x * src->v.z) + (dest->v.y * src->s) + (dest->v.z * src->v.x);
    ((float *)dest)[3] = (dest->s * src->v.z) + (dest->v.x * src->v.y) - (dest->v.y * src->v.x) + (dest->v.z * src->s);
     */

    /* FIRST ATTEMPT                                     INCORRECT!
     * {1.0, {1.1, 1.2, 1.3}} x {2.0, {2.1, 2.2, 2.3}} = {-5.94, {-10.37,  15.92, -67.32}}
    dest->s   = (dest->s * src->s) - (dest->v.x * src->v.x) - (dest->v.y * src->v.y) - (dest->v.z * src->v.z);
    dest->v.x = (dest->s * src->v.x) + (dest->v.x * src->s) + (dest->v.y * src->v.z) - (dest->v.z * src->v.y);
    dest->v.y = (dest->s * src->v.y) - (dest->v.x * src->v.z) + (dest->v.y * src->s) + (dest->v.z * src->v.x);
    dest->v.z = (dest->s * src->v.z) + (dest->v.x * src->v.y) - (dest->v.y * src->v.x) + (dest->v.z * src->s);
     */
}

And finally, how the function is used...

#include <stdio.h>

#include "quaternion.h"
#define quaternion_print(q) printf(#q" = {% 0.2f, {% 0.2f, % 0.2f, % 0.2f}}\n", q.s, q.v.x, q.v.y, q.v.z)
int main(int argc, char **argv)
{
    Quaternion a = {1.0f, 1.1f, 1.2f, 1.3f};
    Quaternion b = {2.0f, 2.1f, 2.2f, 2.3f};
    Quaternion c = a;

    quaternion_mul(&c, &b);

    quaternion_print(a);
    quaternion_print(b);
    quaternion_print(c);

    return 0;
}

There should be enough code there for you to simply copy and paste it all into a single file for your own testing purposes if necessary.
Thanks!

Last edited by cmtptr (2009-01-28 19:26:04)

Offline

#2 2009-01-28 18:57:41

ghostHack
Member
From: Bristol UK
Registered: 2008-02-29
Posts: 261

Re: [solved] (C) writing floats to struct via pointer argument

If you look at the operations in /*FIRST ATTEMPT */ the first calculation sets dest->s to the correct result of the calculation.

The second calculation then uses this new value in dest->c to calculate dest->v.x leading to an incorrect result being assigned to dest->v.x.

This is then continued in the other operations.  So by the time you come to calculate dest->v.z all the inputs to the calculation from the 'dest' structure are the results of previous calculations and all the items in the original structure have been overwritten.

Offline

#3 2009-01-28 19:25:01

cmtptr
Member
Registered: 2008-09-01
Posts: 135

Re: [solved] (C) writing floats to struct via pointer argument

ghostHack wrote:

If you look at the operations in /*FIRST ATTEMPT */ the first calculation sets dest->s to the correct result of the calculation.

The second calculation then uses this new value in dest->c to calculate dest->v.x leading to an incorrect result being assigned to dest->v.x.

This is then continued in the other operations.  So by the time you come to calculate dest->v.z all the inputs to the calculation from the 'dest' structure are the results of previous calculations and all the items in the original structure have been overwritten.

Oh, good lord, now I feel like an idiot.  You're exactly right.  I got so caught up in looking too deep into it that I missed the blatant, obvious logical error.  Thank you so much for that!
What's even more discouraging is the number of clues that are so obvious now that I know the answer. tongue

Last edited by cmtptr (2009-01-28 19:32:04)

Offline

Board footer

Powered by FluxBB