Einen Vektor normalisieren

28

Um einen Vektor zu normalisieren , skalieren Sie ihn auf eine Länge von 1 ( ein Einheitsvektor ), während Sie die Richtung konsistent halten.

Zum Beispiel, wenn wir einen Vektor mit drei Komponenten, normalisieren wollten u , würden wir zuerst finden seine Länge:

| u | = sqrt (u x 2 + u y 2 + u z 2 )

... und skalieren Sie dann jede Komponente um diesen Wert, um einen Vektor der Länge 1 zu erhalten.

û = u ÷ | u |


Die Herausforderung

Ihre Aufgabe ist es, ein Programm oder eine Funktion zu schreiben, die bei einer nicht leeren Liste von vorzeichenbehafteten ganzen Zahlen diese als Vektor interpretiert und normalisiert. Dies sollte beispielsweise für eine beliebige Anzahl von Dimensionen funktionieren (Testfälle auf zwei Dezimalstellen gerundet):

[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]

Regeln:

  • Sie können davon ausgehen, dass die Eingabeliste:
    • Haben Sie mindestens ein Element ungleich Null
    • Enthalten Sie nur Zahlen innerhalb des Standard-Gleitkommabereichs Ihrer Sprache
  • Ihre Ausgabe sollte auf mindestens zwei Dezimalstellen genau sein . Die Rückgabe von Brüchen / Symbolwerten mit "unendlicher Genauigkeit" ist ebenfalls zulässig, wenn Ihre Sprache die Daten auf diese Weise intern speichert.
  • Einreichungen sollten entweder ein vollständiges Programm sein, das E / A ausführt, oder eine Funktion. Übergebene Funktionen können entweder eine neue Liste zurückgeben oder die vorhandene Liste ändern.
  • Eingebaute Vektorfunktionen / -klassen sind erlaubt. Wenn Ihre Sprache einen Vektortyp hat, der eine beliebige Anzahl von Dimensionen unterstützt, können Sie eine davon als Eingabe verwenden.

Da dies ein Wettbewerb ist, sollten Sie versuchen, die kürzestmögliche Lösung (in Byte) zu erzielen.

FlipTack
quelle
Muss es für jede mögliche Eingabe mindestens zwei Dezimalstellen geben (was für keinen Standardtyp von Gleitkommawerten möglich ist) oder nur für die von Ihnen angegebenen Beispiele? Zum Beispiel liefert die Antwort von Steadybox 2 Dezimalstellen für alle Ihre Tests, aber er verwendet Ints für die Summe der Quadrate, was natürlich für fast alle Eingaben fehlschlägt (z. B. [0.1, 0.1]).
Christoph
... jetzt warten wir nur auf eine Sprache mit eingebauter
Normfunktion
Es sollte mindestens 2dp für jede mögliche Eingabe @Christoph
FlipTack
@FlipTack, aber das schließt grundsätzlich alle Sprachen aus, da Gleitkommazahlen größere Exponenten als Mantissen haben, was bedeutet, dass sie nicht immer genau genug sind, um Dezimalstellen zu haben.
Christoph
Warum normalisieren sich die 6 im 4. Beispiel und die -6 im 5. Beispiel nicht auf 1 und -1?
Mast

Antworten:

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
quelle
9
n0t what I expected /
YSC
10

JavaScript (ES6), 31 bytes

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

Test cases

Arnauld
quelle
10

Mathematica, 9 bytes

Normalize

Try it online!

J42161217
quelle
12
Or #/Norm@#& for the same byte count.
Martin Ender
9

J, 8 bytes

%+/&.:*:

Try it online!

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

FrownyFrog
quelle
Love the way of getting the magnitude.
cole
1
@cole 1 byte longer: %1%:@#.*:
FrownyFrog
6
Could you please add an explanation for the uninitiated in J?
MechMK1
% (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
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
8

Jelly, 5 3 bytes

÷ÆḊ

Try it online!, or see the test suite

Saved 2 bytes thanks to miles!

caird coinheringaahing
quelle
3 bytes with ÷ÆḊ
miles
@miles Huh, never knew about that builtin. Thanks
caird coinheringaahing
unfortunately that built-in gives +ve mod for scalars per TIO examplelike absolute value .. the problem requested keeping the sign
jayprich
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
quelle
+1. s=0,i=0 instead of s=i=0 saves one
xanoetux
I love the use of s[-i]but sadly *--v/=sqrt(s); is 1 byte shorter.
Christoph
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
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
4

Python, 47 46 bytes

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

Try it online!

PattuX
quelle
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
quelle
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
quelle
We got the same answer!
kamoroso94
@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
Nah I'll just remove mine. You put more effort into your answer :P
kamoroso94
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
quelle
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
quelle
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)

ბიმო
quelle
2

Funky, 42 bytes

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

Try it online!

ATaco
quelle
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
quelle
I am just lurking codegolf every now and then, but isn't this invalid C++, given "#import", which is a Microsoft specific extension?
phresnel
@phresnel #import works at least with GCC, Clang and MinGW, too. But, yeah, it's not standard C++.
Steadybox
@phresnel I forgot to specify gcc. Fixed.
Colera Su
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
quelle
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
quelle
Train for less: ⊢÷.5*⍨(+/×⍨)
Adám
@Adám thanks alot! I've been trying for hours, couldn't get any train to work
Uriel
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
(+/×⍨) -> +.×⍨
ngn
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
quelle
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
quelle
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
quelle
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
quelle
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
quelle
1
Save some bytes by using sum{...} instead of map{...}.sum
G B
0

APL NARS 12 Characters

f←{⍵÷√+/⍵*2}
RosLuP
quelle
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
@Uriel Nars Apl in the few I know would write with Unicode so number of bytes should be 12x2
RosLuP
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
quelle
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
quelle