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.


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

9
n0t what I expected /
YSC

10

JavaScript (ES6), 31 bytes

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

Test cases



9

J, 8 bytes

%+/&.:*:

Try it online!

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


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



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!


+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



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.

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.


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.



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^/




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!


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

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²

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;
}


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)

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

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 (»²).


1

Ruby, 39 35 bytes

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

-4 bytes thanks to G B.


1
Save some bytes by using sum{...} instead of map{...}.sum
G B

0

APL NARS 12 Characters

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

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,","))))))

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!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.