Michael
Michael

Reputation: 5939

Best method for scaling a vector to desired length

The question is about the most robust and the fastest implementation about this rather basic operation:

Given a vector (X,Y) compute the collinear vector of the given length desiredLength. There are at least two methods for that:

One. Find the length of (X,Y) and rescale accordingly:

double currentLength = sqrt(X*X + Y*Y);
if(currentLength == 0) { /* Aye, Caramba! */ }
double factor = desiredLength / currentLength;
X *= factor;
Y *= factor;

Two. Find the direction of (X,Y) and form a vector of desiredLength in that direction:

if(X == 0 && Y == 0) { /* Aye, Caramba! */ }
double angle = atan2(Y, X);
X = desiredLength * cos(angle);
Y = desiredLength * sin(angle);

Which method would be preferable for developing robust app, better numerical stability, faster execution, etc.?

Upvotes: 2

Views: 1171

Answers (3)

aka.nice
aka.nice

Reputation: 9512

Thu shalt better use hypot(x,y) rather than sqrt(x*x+y*y) because a reasonnable implementation of hypot can save you from underflow/overflow conditions.

Examples: hypot(1.0e300,1.0e300) or hypot(1.0e-300,1.0e-300)

Then evaluating x/hypot(x,y) is safe, even in case of gradual underflow (denormalized numbers) like x=1.0e-320, y=0, while evaluating desiredLength/hypot(x,y) might well overflow.

So I would write

double h  = hypot(x,y);
double xd = desiredLength*(x/h);
double yd = desiredLength*(y/h);

You'll get some division by zero exception and nan results if both x,y are zero, so don't bother handling it in a if.

Upvotes: 2

Avi Perel
Avi Perel

Reputation: 422

I would expect method one to be better At least on the performance front as doing sqrt + 2 multiplications should be cheaper than 3 trig operations. I would guess it is also better (or not worse) on the other fronts as well since it involves one approximation (sqrt) instead of 2 (per axis). The sqrt approximation is also "shared" by both x and y.

Upvotes: 1

James Kanze
James Kanze

Reputation: 154007

There's no one right answer, since it will depend on the implementation. However: on any reasonable modern implementation, the four basic operations and sqrt will be exact to the last binary digit. From a quality of implementation point of view, one would hope that the same thing would be true for all of the functions in math.h, but it's less certain. On a machine with IEEE arithmetic (Windows and the mainstream Unix platforms), the four operations and sqrt will be implemented in hardware, where as the trigonomic operations will generally require a software implementation, often requiring tens of more basic operations. Although some floating point processors do support them directly, at least over limited ranges, even then, they are often a magnitude slower than the four basic operations.

All of which speaks in favor of your first implementation, at least with regards to speed (and probably with regards to numeric stability as well).

Upvotes: 2

Related Questions