You may have heard of a dot product back in Trigonometry — it’s a handy operation with a scalar resultant that, with the help of our friend Arccos, can help us find the angle between two vectors a and b. That operation is also called a scalar product. Here, we discuss a different kind of product whose resultant is a vector. Lets quickly refresh on what a vector is, and how it can be used. We’ll then focus on using two three-dimensional vectors and finding their cross product.
As a mathematical tool, a vector has two primary attributes. First, it has a direction. Secondly, and lastly, it has a magnitude. Let us consider the following vector:
V = 2i + 3j + 1k or V = <2, 3, 1>
The two vectors above are the same, but use different syntax. Many classes, Physics courses especially, gravitate towards the former, but we’ll use the latter for its more succinct style. The vector V here has 3 components. An X component (far left), a Y component (middle) and a Z component. In a sense, this is a useful map of our vector. Vectors do not have a position, but if we were to anchor this vector at the origin, the result would look like this: http://www.wolframalpha.com/input/?i=Vector+%3C2%2C+3%2C+1%3E
As can be seen, the vector is offset 2 units along the X axis, 3 along the Y, and 1 along the Z. The magnitude here is the length of the vector. Finally, it is worth noting that this vector, position-less as it may be, can have the tertiary function of defining a point in 3D space.
We now turn our attention to finding the normal vector given two vectors. A normal vector is a vector which is orthogonal (perpendicular) to two vectors.

Above we can see the normal vector of vectors v1 and v2. It’s worth noting that, if v1 and v2 were the X- and Y-axis, then the normal vector would be the Z-axis. Also worth noting is that there are two possible scenarios here for a normal vector; we could reflect the normal vector across v1 so that it now points down, and the resultant vector is still a normal vector, but would have slightly different component values. If it’s hard to realize visually, just rotate the above image in your head until v1 and v2 are above the normal vector, and you’ll have the idea.
It should not be difficult then to convince yourself that if you have two vectors v1 and v2, and you let v1 = <1, 0, 0> and v2 = <0, 1, 0>, then you have two possible normal vectors: n = <0, 1, 0> or n = <0, -1, 0>.
The cross product, then, given two vectors, v1 and v2, finds n.
The process of finding a normal vector given two vectors is very similar to finding the determinant of a matrix, except that the result is a new vector and not a scalar. The next image shows how we can set up a 3×3 matrix with i, j and k values.
Recall that to find a determinant in a 3×3 matrix, we pick a row or column, and the values from that row or column become co-factors of the resulting 2×2 matrix.


Above, row 1 is selected, and the process that becomes one of solving for the determinant of the resulting 2×2 matrices. That operation is then:

Recall, also, that the sign of the co-factors (that is, a, b and c two images above) alternate between positive and negative, such that in a 3×3 matrix, the co-factors are then:
| + – + |
| – + - |
| + – + |
When computing the cross-product, the top row is generally the i j k row. So, if we were finding the cross product of vectors u and v, we then set it up like:
| i j k |
| vx vy vz |
| ux uy uz |
The result, then, is:
n = i * (vy * uz – vz * uy) – j * (vx * uz – vz * ux) + k * (vx * uy – vy * ux);
This simplifies to some n = ai + bj + ck where a, b, and c are the components of our normal vector. That is, n = <a, b, c>.
Now that we’ve done the leg work required to get to the bottom of how we find a normal vector, lets write a cross-product function which will do it for us. It is actually one of the easiest functions to write that are on this site — this primary challenge is in understanding why we write it the way we do, which is why we spend ample time discussing it.
First, we’ll start out defining a simple structure in C that can act as a light-weight three-dimensional vector.
struct Vector3 {
double x;
double y;
double z;
};
We’ll use this structure as arguments to our function to simplify the work, but it should be noted that there are a variety of ways one can choose to implement a Vector3 — a simple array works, as does a full-blown class if your language of choice supports them, and you view any potential overhead as a non-issue.
Next, we start the function.
void cross_product(const struct Vector3 const *v1, const struct Vector3 const *v2, struct Vector3 *result)
{
// ——————
// | i j k
// | v1_x v1_y v1_z
// | v2_x v2_y v2_z
// ——————
// …
}
Here we take pointers to two Vector3 structs (we mark both the pointer and values as const as we will not change them in any way), and the result of the computation will be stored in the result vector that is passed in. We avoid making assumptions about how memory will be used, so no allocations are necessary, and we do not return anything so the function is void.
Finally, we take the above formula for n and write it in.
void cross_product(const struct Vector3 const *v1, const struct Vector3 const *v2, struct Vector3 *result)
{
// ——————
// | i j k
// | v1_x v1_y v1_z
// | v2_x v2_y v2_z
// ——————
result->x = v1->y * v2->z – v1->z * v2->y;
result->y = v1->x * v2->z – v1->z * v2->x;
result->y = result->y * -1;
result->z = v1->x * v2->y – v1->y * v2->x;
}
The primary thing to note here is the multiplication of -1 against the result’s y component. This is again because the co-factors sign varies along the components. Since we are specifically doing 1×3 vectors in a 3×3 context, we only need to be concerned about this value’s sign.
The following code tests the result:
int main()
{
struct Vector3 v1;
v1.x = 3.1;
v1.y = 4.2;
v1.z = 6.5;
struct Vector3 v2;
v2.x = 2.0;
v2.y = 0;
v2.z = 9.1;
struct Vector3 n;
printf(“v1 : <%f, %f, %f>\n”, v1.x, v1.y, v1.z);
printf(“v2 : <%f, %f, %f>\n”, v2.x, v2.y, v2.z);
cross_product(&v2, &v1, &n);
printf(“n : <%f, %f, %f>\n”, n.x, n.y, n.z);
// …
return 0;
}
The result of n is <-38.22, 15.21, 8.4> which is correct. Do note, however, that if the positions of v1 and v2 are switched, the result is then <38.22, -15.21, -8.4>. Both of these are correct results, as they are both normal vectors of v1 and v2, but their direction is different. Also, note that while this vector is called the “normal” vector, it may not be a “normalized” vector (unit vector). A separate procedure is needed to convert your normal vector.