Normalize a Vector

28

2

To normalize a vector is to scale it to a length of 1 (a unit vector), whilst keeping the direction consistent.

For example, if we wanted to normalize a vector with 3 components, u, we would first find its length:

|u| = sqrt(ux2 + uy2 + uz2)

...and then scale each component by this value to get a length 1 vector.

û = u ÷ |u|


The Challenge

Your task is to write a program or function which, given a non-empty list of signed integers, interprets it as a vector, and normalizes it. This should work for any number of dimensions, for example (test cases rounded to two decimal places):

[20]           -> [1]
[-5]           -> [-1]
[-3, 0]        -> [-1, 0]
[5.5, 6, -3.5] -> [0.62, 0.68, -0.40]
[3, 4, -5, -6] -> [0.32, 0.43, -0.54, -0.65]
[0, 0, 5, 0]   -> [0, 0, 1, 0]

Rules:

  • You can assume the input list will:
    • Have at least one non-zero element
    • Only contain numbers within your language's standard floating point range
  • Your output should be accurate to at least two decimal places. Returning "infinite precision" fractions / symbolic values is also allowed, if this is how your language internally stores the data.
  • Submissions should be either a full program which performs I/O, or a function. Function submissions can either return a new list, or modify the given list in place.
  • Builtin vector functions/classes are allowed. Additionally, if your language has a vector type which supports an arbitrary number of dimensions, you can take one of these as input.

This is a contest, so you should aim to achieve the shortest solution possible (in bytes).

FlipTack

Posted 2017-11-26T21:38:55.670

Reputation: 13 242

Does it have to have at least two decimal places for every possible input (which is not possible for any standard type of floating point values) or only for the examples you provide? E.g. Steadybox's answer provides 2 decimal places of precision for all your test but he uses ints for the sum of squares which of course fails for almost all inputs (e.g. [0.1, 0.1]). – Christoph – 2017-11-27T11:07:48.390

... now we just wait for a lang with built-in norm function mapped to one char... – None – 2017-11-27T13:55:49.033

It should be to at least 2dp for every possible input @Christoph – FlipTack – 2017-11-27T16:09:21.413

@FlipTack but that rules out basically all languages because floatings points have bigger exponents than mantissa which means they do not always have enough precision to have any decimal places. – Christoph – 2017-11-27T19:34:22.600

Why don't the 6 in the 4th example and the -6 in the 5th respectively normalize to 1 and -1? – Mast – 2017-11-28T13:03:37.033

@Mast because the vector length, not largest component , needs to be scaled to 1. – FlipTack – 2017-11-28T18:36:58.320

Answers

15

05AB1E, 4 bytes

Code:

nOt/

Try it online!

Explanation

n     # Square each element of the input
 O    # Sum all elements
  t   # Take the square root of the sum
   /  # Divide each element by the square root of the sum

Adnan

Posted 2017-11-26T21:38:55.670

Reputation: 41 965

9n0t what I expected / – YSC – 2017-11-27T10:19:19.130

10

JavaScript (ES6), 31 bytes

a=>a.map(n=>n/Math.hypot(...a))

Test cases

let f =

a=>a.map(n=>n/Math.hypot(...a))

console.log(JSON.stringify(f([20]          ))) // -> [1]
console.log(JSON.stringify(f([-5]          ))) // -> [-1]
console.log(JSON.stringify(f([-3, 0]       ))) // -> [-1, 0]
console.log(JSON.stringify(f([5.5, 6, -3.5]))) // -> [0.62, 0.68, -0.40]
console.log(JSON.stringify(f([3, 4, -5, -6]))) // -> [0.32, 0.43, -0.54, -0.65]
console.log(JSON.stringify(f([0, 0, 5, 0]  ))) // -> [0, 0, 1, 0]

Arnauld

Posted 2017-11-26T21:38:55.670

Reputation: 111 334

10

Mathematica, 9 bytes

Normalize

Try it online!

J42161217

Posted 2017-11-26T21:38:55.670

Reputation: 15 931

12Or #/Norm@#& for the same byte count. – Martin Ender – 2017-11-26T22:03:20.227

9

J, 8 bytes

%+/&.:*:

Try it online!

6 bytes %|@j./ works if the vector is at least 2-dimensional.

FrownyFrog

Posted 2017-11-26T21:38:55.670

Reputation: 3 112

Love the way of getting the magnitude. – cole – 2017-11-26T22:54:57.560

1@cole 1 byte longer: %1%:@#.*: – FrownyFrog – 2017-11-27T04:10:41.483

6Could you please add an explanation for the uninitiated in J? – MechMK1 – 2017-11-27T07:49:11.100

% (divide by) +/ (sum) &.: (under) *: (square). + sums two things. +/ sums a list of things. &.: modifies the preceding operation by applying the following operation first and its inverse afterwards. % normally takes two arguments, but (% f) is a function from x to x % (f x). Most operators automagically work on lists. – Roman Odaisky – 2017-11-28T21:20:43.710

And by the same principles, the function that “normalizes” a vector by adding such a number to each component that they sum to zero is “- +/ % #”. – Roman Odaisky – 2017-11-28T21:26:39.983

8

Jelly, 5 3 bytes

÷ÆḊ

Try it online!, or see the test suite

Saved 2 bytes thanks to miles!

caird coinheringaahing

Posted 2017-11-26T21:38:55.670

Reputation: 13 702

3 bytes with ÷ÆḊ – miles – 2017-11-26T23:46:27.263

@miles Huh, never knew about that builtin. Thanks – caird coinheringaahing – 2017-11-27T00:12:16.490

unfortunately that built-in gives +ve mod for scalars per TIO examplelike absolute value .. the problem requested keeping the sign – jayprich – 2018-05-01T15:34:36.003

6

Octave, 13 bytes

@(x)x/norm(x)

Try it online!

Stewie Griffin

Posted 2017-11-26T21:38:55.670

Reputation: 43 471

6

C,  73  70 bytes

Thanks to @Christoph for saving a byte!

s,i;f(v,n)float*v;{for(s=0;i++<n;)s+=*v**v++;for(;--i;)*--v/=sqrt(s);}

Try it online!

Steadybox

Posted 2017-11-26T21:38:55.670

Reputation: 15 798

+1. s=0,i=0 instead of s=i=0 saves one – xanoetux – 2017-11-27T06:10:25.747

I love the use of s[-i]but sadly *--v/=sqrt(s); is 1 byte shorter. – Christoph – 2017-11-27T11:08:46.610

1

@xanoetux Thanks, but I need to initialize the variables inside the function, because functions need to be reusable. Besides, as global variables, s and i are automatically initialized to 0. (Turns out I don't need to initialize i in the function, because the function always leaves it at value 0)

– Steadybox – 2017-11-27T11:30:05.983

1@Christoph Thanks! I was initially printing the values from the function, so I needed v[-i] to get the values in correct order. – Steadybox – 2017-11-27T11:31:21.423

4

Python, 47 46 bytes

lambda v:[e/sum(e*e for e in v)**.5for e in v]

Try it online!

PattuX

Posted 2017-11-26T21:38:55.670

Reputation: 361

4

Julia, 9 bytes

normalize

Try it online!

Uriel

Posted 2017-11-26T21:38:55.670

Reputation: 11 708

3

CJam, 9 bytes

{_:mhzf/}

Try it online!

Explanation

_    e# Duplicate input.
:mh  e# Fold hypothenuse-length over the vector. This gives the norm, unless the vector
     e# has only one component, in which case it just gives that component.
z    e# Abs. For the case of a single negative vector component.
f/   e# Divide each vector component by the norm.

Martin Ender

Posted 2017-11-26T21:38:55.670

Reputation: 184 808

3

TI-Basic, 6 bytes

Ans/√(sum(Ans2

Run with {1,2,3}:prgmNAME, where {1,2,3} is the vector to be normalized.

Divides each element in the vector by the square root of the sum of the squares of its elements.

pizzapants184

Posted 2017-11-26T21:38:55.670

Reputation: 3 174

We got the same answer! – kamoroso94 – 2017-11-27T03:24:53.660

@kamoroso94 Whoops! Didn't see yours when I posted this. If you want to add the explanation from this to your answer I'll delete this. – pizzapants184 – 2017-11-27T03:30:05.603

Nah I'll just remove mine. You put more effort into your answer :P – kamoroso94 – 2017-11-27T05:48:38.403

3

R, 23 bytes

function(v)v/(v%*%v)^.5

Try it online!

v%*%v computes the dot product of v with itself.
The function will issue a warning for length 2 or greater vectors.

Giuseppe

Posted 2017-11-26T21:38:55.670

Reputation: 21 077

3

Java (OpenJDK 8), 57 bytes

v->v.stream().map(x->x/v.stream().reduce(0d,Math::hypot))

Try it online!

Olivier Grégoire

Posted 2017-11-26T21:38:55.670

Reputation: 10 647

2

APL (Dyalog), 13 12 10 bytes

1 byte saved thanks to @Adám

2 bytes saved thanks to @ngn

⊢÷.5*⍨+.×⍨

Try it online!

How?

⊢  ÷  .5*⍨  +.  ×⍨
u  ÷    √   Σ   u²

Uriel

Posted 2017-11-26T21:38:55.670

Reputation: 11 708

Train for less: ⊢÷.5*⍨(+/×⍨) – Adám – 2017-11-26T22:15:36.623

@Adám thanks alot! I've been trying for hours, couldn't get any train to work – Uriel – 2017-11-26T22:27:36.563

We should do something about that, as it is really not so hard. When you have a monadic function (other than the rightmost one), begin a parenthesis to its left (or use a if it isn't derived). Other than that, just swap and for and : {⍵÷.5*⍨+/×⍨⍵}{⍵÷.5*⍨(+/(×⍨⍵))}⊢÷.5*⍨(+/(×⍨⊢))⊢÷.5*⍨(+/(×⍨))⊢÷.5*⍨(+/×⍨) – Adám – 2017-11-27T10:13:36.187

(+/×⍨) -> +.×⍨ – ngn – 2017-11-28T07:15:25.113

2

MATL, 5 bytes

t2&|/

Try it online!

I'm not entirely sure this is the shortest way to do this. First, we duplicate the input, then select the second output type of | (which is either abs, norm or determinant). Finally, we divide the input by the norm.

Alternative for 7 bytes:

t2^sX^/

Stewie Griffin

Posted 2017-11-26T21:38:55.670

Reputation: 43 471

2

Haskell, 29 bytes

f x=map(/sqrt(sum$(^2)<$>x))x

Try it online!

Or for 1 byte more pointfree: map=<<flip(/).sqrt.sum.map(^2)

ბიმო

Posted 2017-11-26T21:38:55.670

Reputation: 15 345

2

Funky, 42 bytes

a=>(d=a::map)(c=>c/d(b=>b^2)::reduce@+^.5)

Try it online!

ATaco

Posted 2017-11-26T21:38:55.670

Reputation: 7 898

2

C++ (gcc), 70 bytes

Input by std::valarray<float>. Overwrites the original vector.

#import<valarray>
int f(std::valarray<float>&a){a/=sqrt((a*a).sum());}

Try it online!

Colera Su

Posted 2017-11-26T21:38:55.670

Reputation: 2 291

I am just lurking codegolf every now and then, but isn't this invalid C++, given "#import", which is a Microsoft specific extension? – phresnel – 2017-11-27T11:01:07.073

@phresnel #import works at least with GCC, Clang and MinGW, too. But, yeah, it's not standard C++. – Steadybox – 2017-11-27T11:36:44.027

@phresnel I forgot to specify gcc. Fixed. – Colera Su – 2017-11-27T12:30:10.667

2

Ohm v2, 5 bytes

D²Σ¬/

Try it online!

Cinaski

Posted 2017-11-26T21:38:55.670

Reputation: 1 588

2

Common Lisp, 69 bytes

(lambda(v)(mapcar(lambda(x)(/ x(sqrt(loop as y in v sum(* y y)))))v))

Try it online!

Renzo

Posted 2017-11-26T21:38:55.670

Reputation: 2 260

1

Husk, 8 7 bytes

´(Ṁ/√ṁ□

Try it online!

ბიმო

Posted 2017-11-26T21:38:55.670

Reputation: 15 345

1

Ruby, 39 35 bytes

->v{v.map{|x|x/v.sum{|x|x*x}**0.5}}

-4 bytes thanks to G B.

m-chrzan

Posted 2017-11-26T21:38:55.670

Reputation: 1 390

1Save some bytes by using sum{...} instead of map{...}.sum – G B – 2017-11-27T11:34:14.270

1

C# (.NET Core), 51+64=115 bytes

v=>v.Select(d=>d/Math.Sqrt(v.Select(x=>x*x).Sum()))

Try it online!

+64 bytes for the using System;using System.Collections.Generic;using System.Linq;

C# (.NET Core), 94+13=107 bytes

v=>{var m=0d;foreach(var x in v)m+=x*x;for(int i=0;i<v.Length;)v[i++]/=Math.Sqrt(m);return v;}

Try it online!

+13 bytes for using System;

The non-Linq approach

DeGolfed

v=>{
    var m=0d;
    foreach (var x in v)
        m+=x*x;

    for (int i=0; i < v.Length;)
        v[i++] /= Math.Sqrt(m);

    return v;
}

Ayb4btu

Posted 2017-11-26T21:38:55.670

Reputation: 541

1

Perl 5, 45 + 1 (-a) = 46 bytes

say$_/sqrt eval join'+',map"($_)**2",@F for@F

Try it online!

Xcali

Posted 2017-11-26T21:38:55.670

Reputation: 7 671

1

Pip, 10 bytes

9 bytes of code, +1 for -p flag.

g/RT$+g*g

Takes the vector as separate command-line arguments. Try it online!

How it works

      g*g  Arglist, multiplied by itself itemwise
    $+     Sum
  RT       Square root
g/         Divide arglist itemwise by that scalar
           Result is autoprinted (-p flag to format as list)

DLosc

Posted 2017-11-26T21:38:55.670

Reputation: 21 213

1

Pyth, 5 bytes

cR.aQ

Try it online: Test Suite

Explanation:

cR.aQQ   implicit Q at the end
c        divide
 R   Q   each element of the input
  .aQ    by the L2 norm of the input vector

Jakube

Posted 2017-11-26T21:38:55.670

Reputation: 21 462

1

Perl 6, 25 bytes

{$_ »/»sqrt sum $_»²}

Try it online!

$_, the list argument to the function, is divided elementwise (»/») by the square root of the sum of the squares of the elements (»²).

Sean

Posted 2017-11-26T21:38:55.670

Reputation: 4 136

0

APL NARS 12 Characters

f←{⍵÷√+/⍵*2}

RosLuP

Posted 2017-11-26T21:38:55.670

Reputation: 3 036

You don't have to count f← in your byte count, since you can use the dfns without it. By the way, is a single byte in NARS? I'm not familiar with it, so just asking – Uriel – 2017-11-26T22:48:37.077

@Uriel Nars Apl in the few I know would write with Unicode so number of bytes should be 12x2 – RosLuP – 2017-11-27T06:01:18.150

0

Add++, 38 bytes

L?!*,EL2@xa@pBcB`s0.5^VcALG$xVcGa@BcB/

Try it online!

caird coinheringaahing

Posted 2017-11-26T21:38:55.670

Reputation: 13 702

0

Google Sheets, 65 bytes

=ArrayFormula(TextJoin(",",1,If(A:A="","",A:A/Sqrt(Sumsq(A:A)))))

The input list is in column A with one entry per cell. This is how spreadsheets would normally use lists. Unfortunately, this would normally result in a long list of ,0,0,0,0,0,.... at the end so we have to ignore those with the If Blank then Blank else Math logic.

If it was all in one cell, instead, the solution would be 95 bytes:

=ArrayFormula(TextJoin(",",1,If(Split(A1,",")="","",Split(A1,",")/Sqrt(Sumsq(Split(A1,","))))))

Engineer Toast

Posted 2017-11-26T21:38:55.670

Reputation: 5 769

0

Japt, 6 bytes

®/Ux²q

Try it here


Explanation

Map over the input array (®), divide (/) the current element by the square root (q) of the sum (x) of the elements in the input (U) squared (²).

Shaggy

Posted 2017-11-26T21:38:55.670

Reputation: 24 623

0

Swift 4, 44 bytes

{a in a.map{$0/sqrt(a.reduce(0){$0+$1*$1})}}

Recalculates the vector norm for every component, but at least it's terse!

Alexander - Reinstate Monica

Posted 2017-11-26T21:38:55.670

Reputation: 481

0

Clojure, 47 bytes

#(for[i %](/ i(Math/sqrt(apply +(map * % %)))))

This version calculates the norm only once and should look a bit more obscure for non-clojurists (% is the input argument):

#(map / %(repeat(Math/sqrt(apply +(map * % %)))))

NikoNyrh

Posted 2017-11-26T21:38:55.670

Reputation: 2 361

0

Excel VBA, 25 Bytes

Anonymous VBE immediate window function that takes a number vector input from range [1:1] and outputs the normalized vector to the same range

[1:1]=[1:1/SumSQ(1:1)^.5]

Taylor Scott

Posted 2017-11-26T21:38:55.670

Reputation: 6 709

0

Coconut, 40 bytes

x->map((/)$(?,sum(map(t->t*t,x))**.5),x)

I have no idea what I'm doing...

Try it online!

Dennis

Posted 2017-11-26T21:38:55.670

Reputation: 196 637