On picking an orthogonal vector (and combing coconuts)

Consider the following problem:

Given a non-zero vector v in 3D space, find a non-zero vector w orthogonal to v (i.e. such that v.w = 0).

At first sight, this seems easy. For every possible v there are an infinite number of orthogonal vectors lying in a plane:

We just need to pick one. But it’s not as trivial as it may seem.

First attempts

The following vector satisfies v.w1 = 0:

$$\mathbf{v} = \begin{bmatrix}x \\ y \\ z \end{bmatrix}
\mathbf{w_1} = \begin{bmatrix}-y \\ x \\ 0 \end{bmatrix}
\mathbf{v} . \mathbf{w_1} = x * -y + y * x + z * 0 = 0

Unfortunately that w1 vector can be zero, for instance when v = [0 0 1]. The original problem requires a non-zero vector.

Let’s try another one:

$$\mathbf{v} = \begin{bmatrix}x \\ y \\ z \end{bmatrix}
\mathbf{w_2} = \begin{bmatrix}0 \\ -z \\ y \end{bmatrix}
\mathbf{v} . \mathbf{w_2} = x * 0 + y * -z + z * y = 0

Again, it works most of the time, except in some cases, for instance v = [1 0 0].

How about adding them together? Certainly w1 and w2 cannot be both zero at the same time!

$$\mathbf{v} = \begin{bmatrix}x \\ y \\ z \end{bmatrix}
\mathbf{w_3} = \begin{bmatrix}-y \\ x-z \\ y \end{bmatrix}
\mathbf{v} . \mathbf{w_3} = x * -y + y * (x-z) + z * y = 0

Alas, this still doesn’t work all the time: it fails with v = ![1 0 1].

Should we try harder? Isn’t there a linear combination of these that will work all the time?

Well, no. There isn’t.

You can’t comb a coconut

Sadly, the hairy ball theorem, a consequence of Brouwer’s fixed-point theorem, states that any continuous function f that maps the set of unit vectors to orthogonal vectors takes the value zero somewhere.

Whichever way you look at the sphere of unit vectors, a continuous tangent field will always have a zero point:

Most of the maths operations we usually do (adding, multiplying, taking square roots, etc.) are continuous. Fortunately, we are not limited to them: we can use a simple if() construct to create a discontinuity that will save us.

A very good implementation

Here is my personal implementation of the orthogonal vector problem. It is very good. It has excellent numerical stability. It only does one test. It is short. It is beautiful. I really hope you consider using it.

/* Always works if the input is non-zero.
 * Doesn’t require the input to be normalised.
 * Doesn’t normalise the output. */
vec3 orthogonal(vec3 v)
    return abs(v.x) > abs(v.z) ? vec3(-v.y, v.x, 0.0)
                               : vec3(0.0, -v.z, v.y);

Many implementations, such as Ogre3D’s, have additional tests or operations to perform this task, and use epsilons and normalised vectors to avoid singularities.

But our only test is actually enough: if |x|>|z|, it means the largest component in absolute value in v is either x or y. So we build a vector using x and y. Otherwise, the largest component in absolute value is either y or z. So we build a vector using y and z. That way, we ensure that the length of our returned vector never, ever comes near zero.

Whether some given code will cause inefficient branching is often unclear. In our case, it is very likely that the ternary operator will actually be branchless, with some help of the compiler and the hardware.

That said, how about we try to get rid of the ternary operator, just for fun?

Going branchless for fun

Let’s see. We had these two candidate vectors, w1 and w2, which worked almost always except when specific values of v caused them to be zero. And whatever the constant k we may pick, a vector of the form w1 + k w2 will eventually take the value zero for some value of v, too, because of the hairy ball theorem.

Now here comes the trick. Instead of using a constant k, we use a function f(x,y,z). This is what our w vector looks like:

$$\mathbf{v} = \begin{bmatrix}x \\ y \\ z \end{bmatrix}
\mathbf{w} = \begin{bmatrix}-y \\ x- z * f(x,y,z) \\ y * f(x,y,z) \end{bmatrix}
\mathbf{v} . \mathbf{w} = \cdots = 0

From now I shall assume that v is a unit vector.

What can cause w to be zero, then?

One necessary condition is y = 0. When y ≠ 0 we can chose anything we want for f(x,y,z), it’ll always give us a good orthogonal vector. This restricts the problem to the y = 0 circle, giving us the useful equality x² + z² = 1.

The other condition is x = z*f(x,y,z). So if we manage to build a function f such that f(x,y,z) never equals x/z, we win.

Using x² + z² = 1 we can plot all the possible values for x/z as a function of x. It will show us, for a given x, the values that f cannot take:

The almost vertical slopes you see go to infinity upwards and downwards. As expected, this prevents us from using a continuous function: it would obviously cross one of these walls at some point.

Well, let’s try a non-continuous function, then. What are our options?

  • fmod
  • floor, ceil, round
  • fract

Here is one that I came up with and which works reasonably well:

$$f(x,y,z) = \mathrm{fract}(|x| + \frac{1}{2})$$

Look how it nicely avoids x/z:

And finally, our resulting branchless code:

/* Requires the input to be normalised.
 * Doesn’t normalise the output. */
vec3 orthogonal(vec3 v)
    float k = fract(abs(v.x) + 0.5);
    return vec3(-v.y, v.x - k * v.z, k * v.y);

I find it highly unlikely that this second version will perform better than the branching one. However, I haven’t put much thought into it and maybe someone will come up with a much better solution using the ideas presented here. Have fun!

  • Posted: 2013-09-21 11:25 (Updated: 2013-09-21 11:34)
  • Author: sam
  • Categories: maths optim

Attachments (4)

Download all attachments as: .zip


1. b.stolk@gmail.com -- 2013-09-21 17:43

That seems pretty efficient. What I used to do was much more involved:

  • find smallest |coord| in vector: x,y, or z.
  • cross vector with with unit axis of coord found in step 1.

which is slower due to two tests.

About your version: you can easily take out the branch by simply computing both vectors and blending. In x86 SSE this would look like:

#include <immintrin.h>
return _mm_blend_ps( zy_solution, yx_solution, x_is_larger );

PS: I used the branchless selection a lot when programming the Cell's SPU. That thing would execute code at such an insane ridiculous speed as long as you avoid branching and used SoA. In the CPU's case, you would use the spu_sel() intrinsic.

2. anonymous -- 2014-02-25 09:04

What about the correctness of this function?

Vec3 orthogonal(const Vec3& u, const Vec3& v){

float dt = dot(v, u) / dot(u, u); return Vec3( v - u*dt );


3. sam -- 2014-02-25 10:44

@anonymous This function will work, but it requires you to provide a vector v that is not collinear with u. Which brings you back to square one: given u, how do you pick v?

4. samira -- 2014-11-05 22:53

This is interesting, thanks.

5. Bas -- 2015-06-18 23:22

I've thought about this lately and wouldn't it work to do this?

cross(v, v.zxy * (-1,1,-1))

It's so simple there has to be something wrong with it, but I can't think of any case that would make it fail.

6. sam -- 2015-06-18 23:59

@Bas: Yes, there is necessarily something wrong, since the fixed-point theorem applies to this function. In this case, a simple counterexample is v = [1 1 -1].

7. anonymous -- 2017-10-13 08:22

The prospect that two randomly picked vectors are orthogonal to each other is precisely zero for any sensible probability distribution on a vector space. So it sounds like you're disappeared some relevant situation here.http://www.aoneassignments.com

8. anonymous -- 2017-11-08 10:38

Play sonic games free online from this webpage http://sonicgames.xyz and play online sonic games. For play these sonic games there are no need to download anything.

9. anonymous -- 2017-12-28 14:20

As per my sight the Orthogonal vector is a vector uprooted by 90° regarding a given vector !!!!!! their convergence makes a point of 90°. Assignment Writing Service

10. anonymous -- 2018-01-15 08:39

You have posted a great tutorial which i like it a lot. I must say students should read this article so that they can learn from it. Purchase grass mats from http://www.grassmatsuk.com

11. anonymous -- 2018-01-15 13:21

Very good information about the On picking an orthogonal vector which practically makes it work. I am very happy to see this post. Thanks. To get gym mats Click here http://www.rubbergymmats.co.uk/

12. Thesis Writing Help -- 2018-02-10 10:06

https://www.dissertationwriting.uk/ I’m really impressed with your article, such great & usefull knowledge you mentioned here

13. Online Law Homework Help -- 2018-02-10 10:07

https://lawassignmentshelp.com/ I am so happy to read this. This is the kind of manual that needs to be given and not the random misinformation that's at the other blogs.

14. anonymous -- 2018-02-11 20:26

It is interesting how you combine the maths with coconuts! Pretty good stuff, we like it. www.derbydrivewaypros.co.uk

15. Autocad Assignment Help -- 2018-02-22 14:06

Dissertation Guidance Provides Quality Online Dissertation Help For Students. http://www.autocadhelp.net/

16. Harvard Business Review case analysis -- 2018-02-22 14:08

This A Good Way To Appreciate The Teacher As They Put Their Efforts To Train Students. UK Dissertation Writers Appreciates The Teachers. http://casegurus.com/

17. anonymous -- 2018-03-02 15:42

A great example of how a competent post should be made, thanks, others should learn from your blog http://19216811-admin.com/

18. anonymous -- 2018-03-13 11:42

Windows 10 turns on Bluetooth on your computer system or tool as well as starts looking for tools it could link to. When you see your Bluetooth mouse in the checklist of devices, tap on it. For how to take screen shot in windows 10 go to https://windowsclassroom.com/how-to-take-screenshot-on-windows-8/

19. anonymous -- 2018-03-20 11:34

Informative post. There are very practical points shared in this post. These points are very helpful in out practical life. Thanks for it. Carry on it. To get heavy duty shelving Click here http://ukheavydutyshelving.uk/

20. anonymous -- 2018-03-28 07:18

What a great informative post. I like it and appreciate your writing skills. You have done good job. Keep it up.Get online epdm rubber roofing click this http://epdmrubberroofinguk.co.uk/

21. anonymous -- 2018-04-27 17:47

This article does talk about lot of things in physics which we can see in our academic classrooms teaching. This information can help me to gain more knowledge on this topic. I generally read rush my paper writing service blog tutorials and use them as my examination time reference one as additional material.

22. anonymous -- 2018-05-10 11:13

Panda Express is a private subsidiary food service industry that has Chinese cuisine as the genre. http://pandaexpress.surveyh.info/ was founded in the year 1983 about 34 years ago at Glendale California United States.

23. dom -- 2018-05-17 08:27

Most of us have probably, at some point, written code resembling this:

Perform velocity damping velocity -= velocity * 0.01f; … or probably the more correct:

Per-second damping coefficient float const D = 10.0f; Damp velocity according to timestep velocity -= velocity * D * delta_time; Per-second damping coefficient float const D = 10.0f; Damp velocity (framerate-independent) velocity *= pow(1.f - D / 60.f, 60.f * delta_time); Per-second damping coefficient float const D = 10.0f; Exponentiation base for velocity damping float const D2 = pow(1.f - D / 60.f, 60.f); Damp velocity (framerate-independent) velocity *= pow(D2, delta_time); /* Build a unit quaternion representing the rotation

  • from u to v. The input vectors need not be normalised. */

quat quat::fromtwovectors(vec3 u, vec3 v) {

float norm_u_norm_v = sqrt(dot(u, u) * dot(v, v)); float real_part = norm_u_norm_v + dot(u, v); vec3 w; if (real_part < 1.e-6f * norm_u_norm_v) {

/* If u and v are exactly opposite, rotate 180 degrees

  • around an arbitrary orthogonal axis. Axis normalisation
  • can happen later, when we normalise the quaternion. */

real_part = 0.0f; w = abs(u.x) > abs(u.z) ? vec3(-u.y, u.x, 0.f)

: vec3(0.f, -u.z, u.y);

} else {

/* Otherwise, build quaternion the standard way. */ w = cross(u, v);

} return normalize(quat(real_part, w.x, w.y, w.z));

cheap essay writing service uk

25. michaelt.harwell@gmail.com -- 2018-06-05 07:20

Science Channel’s are giving a complete knowledge to its viewers about every thing students write done dissertation on this subjects and show its importance. https://paymetodoyourhomework.xyz

26. subhanmahmud76@gmail.com -- 2018-06-05 07:21

I loved the way you discuss the topic great work thanks for the share Your informative post. https://pythonassignments.xyz

27. brante.broderick@gmail.com -- 2018-06-05 07:22

I’m really impressed with your article, such great & usefull knowledge you mentioned here https://www.sociologyassignments.com

28. Food -- 2018-06-09 09:59

I was surfing net and fortunately came across this site and found very interesting stuff here. Its really fun to read. I enjoyed a lot. Thanks for sharing this wonderful information. Food

29. roberta.gray12@gmail.com -- 2018-06-21 09:09

Thanx For Sharing Such Useful Post Keep It Up :) Assignment Help Online

30. Eden Carter -- 2018-06-21 14:07

I’m Really Impressed With Your Article, Such Great & Usefull Knowledge You Mentioned Here Case Study Writing Services

Add New Comment