Weird behavior on allocation...what's going on?

Z

Zerex71

Greetings,

I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.

Here is the offending code snippet in the main():

Quaternion q1 = new Quaternion(5.0, 7.0, 6.6, -8.0);
q1.print();
Quaternion q2 = new Quaternion(-4.0, -3.0, 2.0, 1.0);
System.out.println("q1 and q2");
q1.print();
q2.print();
Quaternion q3 = new Quaternion();
System.out.println("q3 before multiplication");
q3.print();
q3 = Quaternion.mul(q1, q2);
System.out.println("q3 after multiplication");
q3.print();


Here is the output I get:

quaternion: 5.000 + 7.000i + 6.600j - 8.000k
q1 and q2
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
q3 before multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k
q3 after multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k

Can anyone explain to me what I'm missing? I'm assuming that by doing
new, I get two separate instances, init'd as shown, so that q1 and q2
are not the same thing. FYI, most of the code in the Quaternion class
is static, so I'm guessing it has to do with some subtle but insidious
misuse of the static keyword in my class definition. Please help!
Thanks.

Mike
 
U

Uwe Plonus

Zerex71 said:
Greetings,

Can anyone explain to me what I'm missing? I'm assuming that by doing
new, I get two separate instances, init'd as shown, so that q1 and q2
are not the same thing. FYI, most of the code in the Quaternion class
is static, so I'm guessing it has to do with some subtle but insidious
misuse of the static keyword in my class definition. Please help!
Thanks.
Hi,

it seems that the static causes your problems. Without the class it is
very difficult to show the problems but it seems that the real and
imaginary parts are saved in statics and so only one instance of a
quarternion can exists (what dows not make sense a lot).

Uwe
 
O

Oliver Wong

Zerex71 said:
Greetings,

I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.

Here is the offending code snippet in the main():

Quaternion q1 = new Quaternion(5.0, 7.0, 6.6, -8.0);
q1.print();
Quaternion q2 = new Quaternion(-4.0, -3.0, 2.0, 1.0);
System.out.println("q1 and q2");
q1.print();
q2.print();
Quaternion q3 = new Quaternion();
System.out.println("q3 before multiplication");
q3.print();
q3 = Quaternion.mul(q1, q2);
System.out.println("q3 after multiplication");
q3.print();


Here is the output I get:

quaternion: 5.000 + 7.000i + 6.600j - 8.000k
q1 and q2
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
q3 before multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k
q3 after multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k

Can anyone explain to me what I'm missing? I'm assuming that by doing
new, I get two separate instances, init'd as shown, so that q1 and q2
are not the same thing. FYI, most of the code in the Quaternion class
is static, so I'm guessing it has to do with some subtle but insidious
misuse of the static keyword in my class definition. Please help!
Thanks.

We would probably want to see the source code for
Quaternion.mul(Quaternion,Quaternion).

Additional info which may help:

* Did you write the Quaternion class, or did a 3rd party write it?
* If you know, are instances of the Quaternion immutable?

- Oliver
 
Z

Zerex71

Hi,

it seems that the static causes your problems. Without the class it is
very difficult to show the problems but it seems that the real and
imaginary parts are saved in statics and so only one instance of a
quarternion can exists (what dows not make sense a lot).

Uwe

Hi Uwe,

Thanks for your quick reply. Yes, I have the four coefficients stored
as statics, because I need them for other operations which I want to
be static, so the user can use the class for math operations without
having to have a specific instance (although this is not a hard
requirement). I just want them to be able to use code like the
following:

q3 = Quaternion.mul(q1, q2)

rather than

q3.mul(q1, q2)

which kind of doesn't make sense because the mul() operation returns a
Quaternion rather than assigning q3's member variables. But, if after
some discussion I come to the realization that this is a "bad" way to
do things, I will change the implementation.

Thanks for your reply.

Mike
 
P

Patricia Shanahan

Zerex71 said:
Greetings,

I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.

Here is the offending code snippet in the main():

Quaternion q1 = new Quaternion(5.0, 7.0, 6.6, -8.0);
q1.print();
Quaternion q2 = new Quaternion(-4.0, -3.0, 2.0, 1.0);
System.out.println("q1 and q2");
q1.print();
q2.print();
Quaternion q3 = new Quaternion();
System.out.println("q3 before multiplication");
q3.print();
q3 = Quaternion.mul(q1, q2);
System.out.println("q3 after multiplication");
q3.print();


Here is the output I get:

quaternion: 5.000 + 7.000i + 6.600j - 8.000k
q1 and q2
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
q3 before multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k
q3 after multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k

Can anyone explain to me what I'm missing? I'm assuming that by doing
new, I get two separate instances, init'd as shown, so that q1 and q2
are not the same thing. FYI, most of the code in the Quaternion class
is static, so I'm guessing it has to do with some subtle but insidious
misuse of the static keyword in my class definition. Please help!
Thanks.

Mike

The code being static may not be a problem, but from your results I'm
guessing that the variables representing the components of the
quaternion are also static, so that at any given time all Quaternion
objects have the same components, the most recently created or
calculated values. For example, the "new Quaternion()" makes the
components zero, and the multiplication is (0,0,0,0)*(0,0,0,0).

If I'm right, you need to remove "static" from those variables. You may
also need to change some methods to either be non-static or to avoid
using "this", explicitly or implicitly.

Patricia
 
O

Oliver Wong

Oliver Wong said:
Zerex71 said:
Greetings,

I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.
[...]

* Did you write the Quaternion class, or did a 3rd party write it?

In either case, have you considered using Sun's Quaternion
implementation?

http://java.sun.com/products/java-m.../J3D_1_3_API/j3dapi/javax/vecmath/Quat4f.html
http://java.sun.com/products/java-m.../J3D_1_3_API/j3dapi/javax/vecmath/Quat4d.html

- Oliver
 
Z

Zerex71

We would probably want to see the source code for
Quaternion.mul(Quaternion,Quaternion).

Additional info which may help:

* Did you write the Quaternion class, or did a 3rd party write it?
* If you know, are instances of the Quaternion immutable?

- Oliver

Oliver,

Here's the class in its entirety...still under development:

package angle;

/**
* @author mfeher
*
*/
public class Quaternion
{
// Methods
// Constructors
Quaternion() {
q0 = 0.0;
q1 = 0.0;
q2 = 0.0;
q3 = 0.0;
}

Quaternion(double q, double qi, double qj, double qk) {
q0 = q;
q1 = qi;
q2 = qj;
q3 = qk;
}

// Conversion methods
// Method to convert a quaternion to Euler angles
static EulerAngles quat2euler(Quaternion q) {
// First we need to convert to a DCM representation
Matrix3x3D DCM = new Matrix3x3D();
DCM = Quaternion.quat2dcm(q);
// Now, using the DCM, extract the Euler angles in radians
double rollRad = Math.atan(DCM.item(1, 2) / DCM.item(2, 2));
double pitchRad = Math.asin(-1*DCM.item(0,2));
double yawRad = Math.atan(DCM.item(0, 1) / DCM.item(0, 0));

// Convert the Euler angles in radians to degrees and store
them
Angle roll = new Angle(Angle.rad2deg(rollRad));
Angle pitch = new Angle(Angle.rad2deg(pitchRad));
Angle yaw = new Angle(Angle.rad2deg(yawRad));
// Set the resultant Euler angles
EulerAngles euler = new EulerAngles(roll, pitch, yaw);
return euler;
}

// Defined mathematical operations
// All of these operations are static so they can be used without
having
// *this* quaternion possess real values
static Quaternion add(Quaternion qa, Quaternion qb) {
// This method performs the defined operation of addition on
two quaternions
// i.e. qc = qa + qb
Quaternion qc = new Quaternion();
qc.q0 = (qa.q0 + qb.q0);
qc.q1 = (qa.q1 + qb.q1);
qc.q2 = (qa.q2 + qb.q2);
qc.q3 = (qa.q3 + qb.q3);
return qc;
}

static Quaternion neg(Quaternion q) {
// This method performs the defined operation of negation of a
quaternion
// i.e. q_neg = neg(q)
Quaternion q_neg = new Quaternion();
q_neg.q0 = -1*q.q0;
q_neg.q1 = -1*q.q1;
q_neg.q2 = -1*q.q2;
q_neg.q3 = -1*q.q3;
return q_neg;
}

static Quaternion sub(Quaternion qa, Quaternion qb) {
// This method performs the defined operation of subtraction
on two quaternions
// i.e. qc = (qa - qb)
Quaternion qc = new Quaternion();
qc.q0 = (qa.q0 - qb.q0);
qc.q1 = (qa.q1 - qb.q1);
qc.q2 = (qa.q2 - qb.q2);
qc.q3 = (qa.q3 - qb.q3);
return qc;
}

static Quaternion mul(Quaternion qa, Quaternion qb) {
// This method performs the defined operation of
multiplication on two quaternions
// i.e. qc = (qa * qb)
// Later on we may implement 3x3 matrix operations whereby we
can
// use those appropriately rather than doing it "directly"
like we do
// here (the less elegant but no less accurate approach).
Quaternion qc = new Quaternion();

qc.q0 = (qa.q0*qb.q0 - qa.q1*qb.q1 - qa.q2*qb.q2 -
qa.q3*qb.q3);
qc.q1 = (qa.q0*qb.q1 + qa.q1*qb.q0 + qa.q2*qb.q3 -
qa.q3*qb.q2);
qc.q2 = (qa.q0*qb.q2 + qa.q2*qb.q0 + qa.q3*qb.q1 -
qa.q1*qb.q3);
qc.q3 = (qa.q0*qb.q3 + qa.q3*qb.q0 + qa.q1*qb.q2 -
qa.q2*qb.q1);

// Note that we can use this method to multiply vector
quaternions, which
// simply means that the scalar parts of such vectors are zero
(i.e. we
// don't need a separate multiplication method to achieve
this).
return qc;
}

static Quaternion inv(Quaternion q) {
// This method returns the inverse of a given quaternion
// i.e. q_inv = q^-1
Quaternion q_inv = new Quaternion();
return q_inv;
}

static Quaternion div(Quaternion qa, Quaternion qb) {
// This method performs the defined operation of division on
two quaternions
// i.e. q_div = qa/qb
Quaternion q_div = new Quaternion();

// First, take the inverse of qb, the denominator
Quaternion qb_inv = Quaternion.inv(qb);

// Now multiply it by the numerator
q_div = Quaternion.mul(qa, qb_inv);
return q_div;
}

static Quaternion conj(Quaternion q) {
// This method returns the conjugate of a given quaternion
// i.e. q_conj = ~q
Quaternion q_conj = new Quaternion();
return q_conj;
}

static Quaternion unit(Quaternion q) {
// This method returns the unit quaternion of a given
quaternion
// i.e. q_unit = |q|
Quaternion q_unit = new Quaternion();
return q_unit;
}

static double index(Quaternion p, Quaternion q) {
// Method to calculate the index of quaternions. If the
quaternions are
// right quaternions, then the index of a right quaternion is
the axis of
// the quaternion scaled by the ratio of lengths.
return 0.0;
}

static double scalar(Quaternion q) {
// Method to determine the scalar part of a quaternion
// Part of the representation in rectangular (Cartesian)
coordinate
return q0;
}

static Vector right(Quaternion q) {
// Method to determine the right part of a quaternion
// Part of the representation in rectangular (Cartesian)
coordinate
Vector right = new Vector(q1, q2, q3);
return right;
}

static void tensor(Quaternion q) {
// Method to determine the tensor part of a quaternion
// Part of the representation in polar coordinates
}

static void versor(Quaternion q) {
// Method to determine the versor part of a quaternion
// Part of the representation in polar coordinates
}

// Later on we may add the "scalar" and "vector" getters for a
quaternion.

// TODO: Change to regular DCM when we implement that
static Matrix3x3D quat2dcm(Quaternion q) {
// Method to convert a given quaternion into a DCM
Matrix3x3D DCM = new Matrix3x3D(); // Change to regular DCM
when we implement that
DCM.array[0][0] = ((q.q0 * q.q0) + (q.q1 * q.q1) - (q.q2 *
q.q2) - (q.q3 * q.q3));
DCM.array[0][1] = 2 * ((q.q1 * q.q2) + (q.q0 * q.q3));
DCM.array[0][2] = 2 * ((q.q1 * q.q3) - (q.q0 * q.q2));
DCM.array[1][0] = 2 * ((q.q1 * q.q2) - (q.q0 * q.q3));
DCM.array[1][1] = ((q.q0 * q.q0) - (q.q1 * q.q1) + (q.q2 *
q.q2) - (q.q3 * q.q3));
DCM.array[1][2] = 2 * ((q.q2 * q.q3) + (q.q0 * q.q1));
DCM.array[2][0] = 2 * ((q.q1 * q.q3) + (q.q0 * q.q2));
DCM.array[2][1] = 2 * ((q.q2 * q.q3) - (q.q0 * q.q1));
DCM.array[2][2] = ((q.q0 * q.q0) - (q.q1 * q.q1) - (q.q2 *
q.q2) + (q.q3 * q.q3));
return DCM;
}

// Lastly, we implement the all-important rotate method - but we
will need
// a 3D vector class to do this
Vector rot(Quaternion q, Vector v_old) {
// Rotate a vector using defined quaternion transformation
Vector v_new = new Vector();
// Perform transformation operations
// v_new = q * v_old * q_inv
return v_new;
}

// Getter methods
double q0() { return q0; }
double q1() { return q1; }
double q2() { return q2; }
double q3() { return q3; }

// Print/inspect methods
// May want to implement toString here instead
void print() {
// Method to print out this quaternion.
// We need some simple handling based on the sign of each
component of
// the quaternion.
String s0, s1, s2, s3;
s0 = String.format("%.3f", q0);

if (q1 < 0)
{
s1 = String.format("- %.3f", -1*q1);
}
else
{
s1 = String.format("+ %.3f", q1);
}

if (q2 < 0)
{
s2 = String.format("- %.3f", -1*q2);
}
else
{
s2 = String.format("+ %.3f", q2);
}

if (q3 < 0)
{
s3 = String.format("- %.3f", -1*q3);
}
else
{
s3 = String.format("+ %.3f", q3);
}

String q = String.format("quaternion: %s %si %sj %sk", s0, s1,
s2, s3);
System.out.println(q);
}

// Attributes
private static double q0;
private static double q1;
private static double q2;
private static double q3;
}
 
P

Patricia Shanahan

Zerex71 wrote:
....
Thanks for your quick reply. Yes, I have the four coefficients stored
as statics, because I need them for other operations which I want to
be static, so the user can use the class for math operations without
having to have a specific instance (although this is not a hard
requirement). I just want them to be able to use code like the
following:

q3 = Quaternion.mul(q1, q2)

You can't just stick "static" on a variable without the consequence of
all objects of the class seeing the same value, which does not make
sense for the coefficients.

Your mul implementation should look like:

public static Quaternion mul(Quaternion q1, Quaternion q2){
Quaternion result = new Quaternion();
result.t = q1.t*q2.t - q1.x*q2.x -
q1.y*q1.y - q1.z*q2.z;
....
return result;
}

The code replacing "..." must never reference a coefficient without
qualifying it with q1, q2, or result.

Patricia
 
A

Alex Hunsley

Zerex71 said:
Greetings,

I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.

All praise Hamilton, for ijk=-1!

Here is the offending code snippet in the main():

Quaternion q1 = new Quaternion(5.0, 7.0, 6.6, -8.0);
q1.print();
Quaternion q2 = new Quaternion(-4.0, -3.0, 2.0, 1.0);
System.out.println("q1 and q2");
q1.print();
q2.print();
Quaternion q3 = new Quaternion();
System.out.println("q3 before multiplication");
q3.print();
q3 = Quaternion.mul(q1, q2);
System.out.println("q3 after multiplication");
q3.print();


Here is the output I get:

quaternion: 5.000 + 7.000i + 6.600j - 8.000k
q1 and q2
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
q3 before multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k
q3 after multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k

Can anyone explain to me what I'm missing? I'm assuming that by doing
new, I get two separate instances, init'd as shown, so that q1 and q2
are not the same thing. FYI, most of the code in the Quaternion class
is static, so I'm guessing it has to do with some subtle but insidious
misuse of the static keyword in my class definition. Please help!

Yup. Sounds like you've defined member variables in your Quaternion
class as static, which is not going to behave the way you want (as you
noticed). The 'new' keyword does indeed make a new object, but 'static'
can be used to cause different objects to all share one piece of data.

In other words, your code is probably like this:

public class Quaternion {
private static float real;
private static float i;
private static float j;
private static float k;


public Quaternion(float real, float i, float j, float k) {
this.i = i; // or you could write Quaternion.i = i
this.j = j;
this.k = k;
this.real = real;
}
}

which isn't correct.
To fix, just remove the 'static' from your member vars:

private float real;
private float i;
private float j;
private float k;

Static member vars can be used for holding data *that applies to your
whole class* or *data which you know is common to every instance you
will make*.

For example, you might have a static member variable recording how many
Quaternion objects had been made so far (and you increment this value in
the constructor), so your code would look like:

public class Quaternion {
private float real;
private float i;
private float j;
private float k;

private static int numQuaternions = 0;

public Quaternion(float real, float i, float j, float k) {
this.i = i; // or even Quaternion.i = i
this.j = j;
this.k = k;
this.real = real;

Quaternion.numQuaternions++; // we just made another
}


// note that this method has to be static in order to
// access the static membar variable, and hence you should
// call it using Quaternion.getNumQuaternionsMade()
public static int getNumQuaternionsMade() {
return numQuaternions;
}
}

(Note that this isn't thread safe, but that's another topic.)

HTH,
lex
 
A

Alex Hunsley

Zerex71 said:
Oliver,

Here's the class in its entirety...still under development:

package angle;
[snip]

A little feedback on your code:

* it's conventional to put your member variables right at the top of the
class
* consider making your Quaternion class immutable. In other words, once
a Quat. is made, it cannot be changed. To do this, make your i, j, k etc
member vars be "public final". Once you do this, you could get rid of
getters.
Immutable objects also remove the chance to mangle objects that other
bits of code are depending on not changing.

lex
 
Z

Zerex71

Zerex71 said:
Greetings,
I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.
[...]

* Did you write the Quaternion class, or did a 3rd party write it?

In either case, have you considered using Sun's Quaternion
implementation?

http://java.sun.com/products/java-m...ucts/java-media/3D/forDevelopers/J3D_1_3_API/...

- Oliver

No, because I want and need to do this myself to understand everything
about them.
I would trust Sun, but generally speaking I do not trust other
people's code - even if it supposedly works,
I still find that oftentimes they are sloppy in their style and not as
elegant as it can be. Besides, I've
trust Microsoft for years now and am getting tired of that
relationship. :)

Mike
 
Z

Zerex71

Zerex71 said:
Here's the class in its entirety...still under development:
package angle;

[snip]

A little feedback on your code:

* it's conventional to put your member variables right at the top of the
class
* consider making your Quaternion class immutable. In other words, once
a Quat. is made, it cannot be changed. To do this, make your i, j, k etc
member vars be "public final". Once you do this, you could get rid of
getters.
Immutable objects also remove the chance to mangle objects that other
bits of code are depending on not changing.

lex

Thanks to everyone who helped - your suggestions will be taken under
consideration! I didn't even consider making them immutable. You're
right though, because now that I think about it, I can declare an
instance of a quaternion and like most doubles, you never really need
to change a particular double (I can always allocate another one as
needed). There's a lot of good suggestions here that I will use. I'm
just glad I wasn't as far off as I originally expected -- I'm having
the double "challenge" of implementing the mathematics behind this
class as well as dealing with the nuances of the Java language. But
it will be so worth it when I'm finished.

Mike
 
O

Oliver Wong

Zerex71 said:
Greetings,
I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.
[...]

* Did you write the Quaternion class, or did a 3rd party write it?

In either case, have you considered using Sun's Quaternion
implementation?

http://java.sun.com/products/java-m...ucts/java-media/3D/forDevelopers/J3D_1_3_API/...

No, because I want and need to do this myself to understand everything
about them.
I would trust Sun, but generally speaking I do not trust other
people's code - even if it supposedly works,
I still find that oftentimes they are sloppy in their style and not as
elegant as it can be. Besides, I've
trust Microsoft for years now and am getting tired of that
relationship. :)

No offense, but if their implementation of Quaternion works, and yours
doesn't, then maybe the level of elegance of their code is higher than the
bar you've set.

If you wish to learn Java programming, then it makes sense to write your
own versions of stuff, for the practice of it. But you'll have to one day
eventually learn to deal with other people's code, because software nowadays
is too complex for a person to implement alone. And then there's also the
principle of "don't reinvent the wheel".

- Oliver
 
C

Chris Uppal

Zerex71 said:
q3 = Quaternion.mul(q1, q2)

I think most Java programmers would expect to write that as:

q3 = q1.mul(q2);

I.e. the mul() operation is an instance method of the Quaternion it is applied
to. If you want the static methods as well, then you can define

public static Quaternion
add(Quaternion q1, Quaternion q2)
{
return q1.add(q2);
}

so that the quoted code snippet would also work.


BTW, you said you were considering making your Quaternions immutable. I think
that's a good idea -- I just wanted to congratulate you on /not/ following the
Sun Quaternion class. /They/ have chosen to make the things mutable, and in
fact an expression like:

q1.add(q2);

/changes/ q1 in place to the the sum of the original value of q1, and the
supplied value for q2 (which /isn't/ changed). I think that's a terrible bit
of design...

(There might have been performance reasons for providing mutating operators
which do change the Quaternion they are applied to, but if so then I don't
think that add() is at all a good name -- addIn() might be better.)

-- chris
 
A

Alex Hunsley

Zerex71 said:
Thanks to everyone who helped - your suggestions will be taken under
consideration! I didn't even consider making them immutable. You're
right though, because now that I think about it, I can declare an
instance of a quaternion and like most doubles, you never really need
to change a particular double (I can always allocate another one as
needed). There's a lot of good suggestions here that I will use. I'm
just glad I wasn't as far off as I originally expected -- I'm having
the double "challenge" of implementing the mathematics behind this
class as well as dealing with the nuances of the Java language. But
it will be so worth it when I'm finished.

Glad to help. I'm interested in seeing your final class when you're
finished too.
 
A

Alex Hunsley

Zerex71 said:
Greetings,
I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion. [...]

* Did you write the Quaternion class, or did a 3rd party write it?
In either case, have you considered using Sun's Quaternion
implementation?

http://java.sun.com/products/java-m...ucts/java-media/3D/forDevelopers/J3D_1_3_API/...

- Oliver

No, because I want and need to do this myself to understand everything
about them.

It's a good practice to write a Quaternion class yourself then.
Two things:

1) to get the most out of this, get poeple (e.g. in this group) to
review your code once you've finished - you may get useful feedback,
like has already happend

2) it's worth testing your code actually works once you've finished. For
example, writing unit tests to see if things behave 'normally' when you
do quaternion arithmetic. This is where knowing properties of
complex/quaternion arithmetic come in very handy. For example, if you
know de Moivre's rule and all that, you can write some tests to check
your quaternion multiplication is behaving sensibly in certain
circumstances, and so on.
I would trust Sun, but generally speaking I do not trust other
people's code - even if it supposedly works,
I still find that oftentimes they are sloppy in their style and not as
elegant as it can be.

A lot depends on how trustworthy the publisher is, and widely used the
code is. For example, I know that Jakarta Common's HTTPClient is used
widely and that means something.

lex
 
Z

Zerex71

I think most Java programmers would expect to write that as:

q3 = q1.mul(q2);

I.e. the mul() operation is an instance method of the Quaternion it is applied
to. If you want the static methods as well, then you can define

public static Quaternion
add(Quaternion q1, Quaternion q2)
{
return q1.add(q2);
}

so that the quoted code snippet would also work.

BTW, you said you were considering making your Quaternions immutable. I think
that's a good idea -- I just wanted to congratulate you on /not/ following the
Sun Quaternion class. /They/ have chosen to make the things mutable, and in
fact an expression like:

q1.add(q2);

/changes/ q1 in place to the the sum of the original value of q1, and the
supplied value for q2 (which /isn't/ changed). I think that's a terrible bit
of design...

(There might have been performance reasons for providing mutating operators
which do change the Quaternion they are applied to, but if so then I don't
think that add() is at all a good name -- addIn() might be better.)

-- chris

Hi Chris,

Thanks for looking over the code. As far as your suggestion, writing
it this way:

q3 = q1.add(q2)

is exactly something I don't want to do. To me, it just looks balky
and I'm not a fan
of doing it that way. But that's just me; I prefer things to look
more like an expression,
i.e. C = f(A,B) like C = Math.hypot(A,B). That kind of thing. I'm
just now getting back
into really learning how to get the most out of the Java language so
there is a lot I want
to investigate.

Unfortunately a lot of what happens to me when I write code, and I
suspect this happens to others,
is that I lay out how I think it should look in the code but then when
I go to call it with real
parameters and variables, I realize it either looks weird, won't
compile, or doesn't seem "clean"
or elegant enough. Of course, I could be being too picky -- after
all, if I have a function thats
purpose is to add two numbers and return their result, isn't that good
enough, regardless of how
it looks?

Also, as to the question of doing it myself...I realize one of the
cool things about languages,
Java especially, if the portability of packages and classes, and while
I would trust "official"
code from Sun et. al. I am trying to achieve two goals by writing such
a class:

1. Apply what my O'Reilly books and other sources tell me about the
nuances and features of Java to practical,
useable examples
2. Develop real classes that will have function as part of my own
application

I get neither experience from my current software engineering gig and
am none too happy about that,
so I code when I can.

Thank you all for writing. This is one of the better Abusenet
discussions I've had lately. :)

Mike
 
O

Oliver Wong

Zerex71 said:
Hi Chris,

Thanks for looking over the code. As far as your suggestion, writing
it this way:

q3 = q1.add(q2)

is exactly something I don't want to do. To me, it just looks balky
and I'm not a fan
of doing it that way. But that's just me; I prefer things to look
more like an expression,
i.e. C = f(A,B) like C = Math.hypot(A,B). That kind of thing.


I think one reason Chris suggested the q3 = q1.add(q2) syntax is that
it's pretty idiomatic of Java. Strings and BigInteger, for example, both
follow that pattern. So a Java programmer whose is used to using Strings and
BigInteger can quickly guess what the syntax is for your Quaternion classes.

That said, notice that Chris suggested a way so that both formulations
are available (i.e. q3 = q1.add(q2) would be equivalent to q3 =
Quaternion.add(q1, q2)) with minimal hassle.

- Oliver
 
A

Alex Hunsley

Zerex71 said:
Greetings,

I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.
[snip]
Btw Zerex, here's a nice little idea...
If you can find a Java mathematical expression parser (e.g.
http://www.singularsys.com/jep/), but one that supports arithmetic on
arbitrary systems that you provide classes for (e.g. Quaternion), you
could also hook that up.
The end result is that your class could provide functionality which
would let the user evaluate an arbitrary algebraic string expression, e.g.:

Hashtable values = new Hashtable();
values.put("a", new Quaternion(1, 2, 3, 4.6));
values.put("b", new Quaternion(0, 0, -1, 3));
values.put("c", new Quaternion(-10.4, 0, 0, 4));

Quaternion result = Quaternion.evaluate("(a*b - c^2)/2");

Or, of course, you (or I) could write an arbitrary expression evaluator
ourselves (or modify an existing one, if possible). The key to writing
it would be that the end-user provides a class (e.g. Quaternion) that
implements an interface, 'AlgebraicField', which means that add, sub,
mult and divide methods are provided... (of course, this interface's
method would be taking Objects and nothing more specific, in order to
remain generalised). Then just turn the expression into a prefix stack
for evaluation, evaluate, and voila!

lex
 
A

Alex Hunsley

Chris said:
I think most Java programmers would expect to write that as:

q3 = q1.mul(q2);

I.e. the mul() operation is an instance method of the Quaternion it is applied
to. If you want the static methods as well, then you can define

public static Quaternion
add(Quaternion q1, Quaternion q2)
{
return q1.add(q2);
}

so that the quoted code snippet would also work.


BTW, you said you were considering making your Quaternions immutable. I think
that's a good idea -- I just wanted to congratulate you on /not/ following the
Sun Quaternion class. /They/ have chosen to make the things mutable, and in
fact an expression like:

q1.add(q2);

/changes/ q1 in place to the the sum of the original value of q1, and the
supplied value for q2 (which /isn't/ changed). I think that's a terrible bit
of design...

Aargh! I didn't know the sun version did that. Naughty sun.
I think it's much easier to go the immutable way, rather than mutable,
when you then end up writing defensive methods in order to be sure your
code is robust, even when used by third parties....
(There might have been performance reasons for providing mutating operators
which do change the Quaternion they are applied to, but if so then I don't
think that add() is at all a good name -- addIn() might be better.)

The minefield of method names and implied information!
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,124
Latest member
JuniorPell
Top