From: Lawrence D'Oliveiro on
Say a vector V is a tuple of 3 numbers, not all zero. You want to normalize
it (scale all components by the same factor) so its magnitude is 1.

The usual way is something like this:

L = math.sqrt(V[0] * V[0] + V[1] * V[1] + V[2] * V[2])
V = (V[0] / L, V[1] / L, V[2] / L)

What I don't like is having that intermediate variable L leftover after the
computation. Here's how to do it in one step:

V = tuple \
(
x
/
math.sqrt
(
reduce(lambda a, b : a + b, (y * y for y in V), 0)
)
for x in V
)

which, incidentally, also works for vectors with dimensions other than 3.
From: Alain Ketterlin on
Lawrence D'Oliveiro <ldo(a)geek-central.gen.new_zealand> writes:

> Say a vector V is a tuple of 3 numbers, not all zero. You want to normalize
> it (scale all components by the same factor) so its magnitude is 1.
>
> The usual way is something like this:
>
> L = math.sqrt(V[0] * V[0] + V[1] * V[1] + V[2] * V[2])
> V = (V[0] / L, V[1] / L, V[2] / L)
>
> What I don't like is having that intermediate variable L leftover after the
> computation.

Well, it also guarantees that the square root is computed once.

> Here's how to do it in one step:
>
> V = tuple \
> ( x / math.sqrt
> (
> reduce(lambda a, b : a + b, (y * y for y in V), 0)
> )
> for x in V
> )
>
> which, incidentally, also works for vectors with dimensions other than 3.

And how many times does it call math.sqrt?

(That's actually not easy to test. Does any insider know the answer?
Does the compiler hoist the math.sqrt(...) out of the implicit loop? I
guess not, because it can't assert that reduce has no side effect.)

Your best bet is to define a function that does the normalization. Your
(local) name will disappear at the end of the call. If you want it to
work for any vector size:

def norm(V):
L = math.sqrt( sum( [x**2 for x in V] ) )
return [ x/L for x in V ]

If you do a lot of such computations, have a look at numpy.

-- Alain.
From: Chris Rebert on
On Fri, Jul 30, 2010 at 4:46 AM, Lawrence D'Oliveiro
<ldo(a)geek-central.gen.new_zealand> wrote:
> Say a vector V is a tuple of 3 numbers, not all zero. You want to normalize
> it (scale all components by the same factor) so its magnitude is 1.
>
> The usual way is something like this:
>
>    L = math.sqrt(V[0] * V[0] + V[1] * V[1] + V[2] * V[2])
>    V = (V[0] / L, V[1] / L, V[2] / L)
>
> What I don’t like is having that intermediate variable L leftover after the
> computation. Here’s how to do it in one step:

I suppose you'd be a fan of the proposed "given"/"where" statement
then (but its prognosis isn't great):
http://www.python.org/dev/peps/pep-3150/

Cheers,
Chris
--
http://blog.rebertia.com
From: John Nagle on
On 7/30/2010 6:46 AM, Alain Ketterlin wrote:
> Does the compiler hoist the math.sqrt(...) out of the implicit loop?

Global optimization in Python? Not in CPython.

The program might redefine math.sqrt from another
thread while the program is running, which would invalidate the
hoisting of the function. That has to be supported.

Shed Skin might do it, but it restricts the language and
doesn't allow the full dynamism of Python.

John Nagle
From: Lawrence D'Oliveiro on
In message <877hkdhyl5.fsf(a)dpt-info.u-strasbg.fr>, Alain Ketterlin wrote:

> Lawrence D'Oliveiro <ldo(a)geek-central.gen.new_zealand> writes:
>
>> What I don't like is having that intermediate variable L leftover after
>> the computation.
>
> Well, it also guarantees that the square root is computed once.

OK, this version should solve that problem, without requiring any new
language features:

V = tuple \
(
x
/
l
for x in V
for l in
(math.sqrt(reduce(lambda a, b : a + b, (y * y for y in V), 0)),)
)