Normalizar un vector


28

Para normalizar un vector es la escala para una longitud de 1 ( un vector unitario ), manteniendo la dirección consistente.

Por ejemplo, si quisiéramos normalizar un vector con 3 componentes, u , primero encontraríamos su longitud:

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

... y luego escala cada componente por este valor para obtener un vector de longitud 1.

û = u ÷ | u |


El reto

Su tarea es escribir un programa o función que, dada una lista no vacía de enteros con signo, lo interprete como un vector y lo normalice. Esto debería funcionar para cualquier cantidad de dimensiones, por ejemplo (casos de prueba redondeados a dos decimales):

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

Reglas:

  • Puede suponer que la lista de entrada:
    • Tener al menos un elemento distinto de cero
    • Solo contiene números dentro del rango de coma flotante estándar de su idioma
  • Su salida debe tener una precisión de al menos dos decimales . También se permite devolver fracciones / valores simbólicos de "precisión infinita", si así es como su idioma almacena internamente los datos.
  • Los envíos deben ser un programa completo que realice E / S o una función. Los envíos de funciones pueden devolver una nueva lista o modificar la lista dada en su lugar.
  • Se permiten funciones / clases de vectores incorporados. Además, si su idioma tiene un tipo de vector que admite un número arbitrario de dimensiones, puede tomar una de estas como entrada.

Este es un concurso de , por lo que debe aspirar a lograr la solución más corta posible (en bytes).


¿Tiene que tener al menos dos lugares decimales para cada entrada posible (que no es posible para ningún tipo estándar de valores de coma flotante) o solo para los ejemplos que proporciona? Por ejemplo, la respuesta de Steadybox proporciona 2 decimales de precisión para todas las pruebas, pero usa ints para la suma de cuadrados que, por supuesto, falla en casi todas las entradas (por ejemplo, [0.1, 0.1]).
Christoph

... ahora solo esperamos un idioma con la función de norma incorporada asignada a un carácter ...
vaxquis

Debe ser de al menos 2dp por cada entrada posible @Christoph
FlipTack

@FlipTack, pero eso descarta básicamente todos los idiomas porque los puntos flotantes tienen exponentes más grandes que mantissa, lo que significa que no siempre tienen la precisión suficiente para tener decimales.
Christoph

¿Por qué el 6 en el 4to ejemplo y el -6 en el 5to, respectivamente, se normalizan a 1 y -1?
Mástil

Respuestas:


15

05AB1E , 4 bytes

Código:

nOt/

Pruébalo en línea!

Explicación

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

99
No es lo que esperaba /
YSC

10

JavaScript (ES6), 31 bytes

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

Casos de prueba



9

J , 8 bytes

%+/&.:*:

Pruébalo en línea!

6 bytes %|@j./funcionan si el vector es al menos bidimensional .


Me encanta la forma de obtener la magnitud.
cole

1
@cole 1 byte más:%1%:@#.*:
FrownyFrog

66
¿Podría agregar una explicación para los no iniciados en J?
MechMK1

% (dividir entre) + / (suma) & .: (debajo) *: (cuadrado). + suma dos cosas. + / suma una lista de cosas. & .: modifica la operación anterior aplicando primero la siguiente operación y luego su inversa. % normalmente toma dos argumentos, pero (% f) es una función de x a x% (fx). La mayoría de los operadores trabajan automáticamente en listas.
Roman Odaisky

Y por los mismos principios, la función que "normaliza" un vector agregando un número tal a cada componente que sumen a cero es "- + /% #".
Roman Odaisky



6

C,  73  70 bytes

¡Gracias a @Christoph por guardar un byte!

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

Pruébalo en línea!


+1. s=0,i=0en lugar de s=i=0
guardar

Me encanta el uso de, s[-i]pero lamentablemente *--v/=sqrt(s);es 1 byte más corto.
Christoph

1
@xanoetux Gracias, pero necesito inicializar las variables dentro de la función, porque las funciones deben ser reutilizables . Además, como variables globales, sy ise inicializan automáticamente a 0. (Resulta que no necesito inicializar ien la función, porque la función siempre la deja en el valor 0)
Steadybox

1
@ Christoph Gracias! Inicialmente estaba imprimiendo los valores de la función, por lo que necesitaba v[-i]obtener los valores en el orden correcto.
Steadybox



3

CJam , 9 bytes

{_:mhzf/}

Pruébalo en línea!

Explicación

_    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

Ejecutar con {1,2,3}:prgmNAME, donde {1,2,3}es el vector a normalizar.

Divide cada elemento en el vector por la raíz cuadrada de la suma de los cuadrados de sus elementos.


¡Tenemos la misma respuesta!
kamoroso94

@ kamoroso94 ¡Vaya! No vi el tuyo cuando publiqué esto. Si desea agregar la explicación de esto a su respuesta, lo eliminaré.
pizzapants184

No, solo quitaré el mío.
Pones

3

R , 23 bytes

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

Pruébalo en línea!

v%*%vcalcula el producto punto de v consigo mismo.
La función emitirá una advertencia para vectores de longitud 2 o mayores.



2

MATL , 5 bytes

t2&|/

Pruébalo en línea!

No estoy completamente seguro de que esta sea la forma más corta de hacerlo. Primero, duplicamos la entrada, luego seleccionamos el segundo tipo de salida de |(que es abs, normo determinant). Finalmente, dividimos la entrada por la norma.

Alternativa para 7 bytes:

t2^sX^/




2

C ++ (gcc), 70 bytes

Entrada por std::valarray<float>. Sobrescribe el vector original.

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

Pruébalo en línea!


Solo estoy al acecho con codegolf de vez en cuando, pero ¿no es este C ++ no válido, dado "#import", que es una extensión específica de Microsoft?
phresnel

@phresnel también #importfunciona al menos con GCC, Clang y MinGW. Pero, sí, no es C ++ estándar.
Steadybox

@phresnel Olvidé especificar gcc. Fijo.
Colera Su


2

APL (Dyalog) , 13 12 10 bytes

1 byte guardado gracias a @ Adám

2 bytes guardados gracias a @ngn

⊢÷.5*⍨+.×⍨

Pruébalo en línea!

¿Cómo?

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

Entrena por menos:⊢÷.5*⍨(+/×⍨)
Adám

@ Adám muchas gracias! Lo he estado intentando durante horas, no pude conseguir ningún tren para trabajar
Uriel

Deberíamos hacer algo al respecto, ya que realmente no es tan difícil. Cuando tenga una función monádica (que no sea la más a la derecha), comience un paréntesis a su izquierda (o use a si no se deriva). Aparte de eso, simplemente cambie y por y : {⍵÷.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()))

Pruébalo en línea!

+64 bytes para el 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;}

Pruébalo en línea!

+13 bytes para using System;

El enfoque no Linq

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 de código, +1 para -pbandera.

g/RT$+g*g

Toma el vector como argumentos separados de la línea de comandos. Pruébalo en línea!

Cómo funciona

      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

Pruébelo en línea: Test Suite

Explicación:

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 $_»²}

Pruébalo en línea!

$_, el argumento de lista para la función, se divide elementwise ( »/») por la raíz cuadrada de la suma de los cuadrados de los elementos ( »²).


1

Ruby, 39 35 bytes

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

-4 bytes gracias a G B.


1
Guarde algunos bytes utilizando en sum{...}lugar demap{...}.sum
GB

0

APL NARS 12 Personajes

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

No tiene que contar f← en su conteo de bytes, ya que puede usar los dfns sin él. Por cierto, ¿hay un solo byte en NARS? No estoy familiarizado con él, por lo que sólo pidiendo
Uriel

@Uriel Nars Apl en los pocos que sé que escribiría con Unicode, por lo que el número de bytes debería ser
12x2

0

Hojas de cálculo de Google, 65 bytes

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

La lista de entrada está en una columna Acon una entrada por celda. Así es como las hojas de cálculo normalmente usarían listas. Desafortunadamente, esto normalmente daría como resultado una larga lista ,0,0,0,0,0,....al final, por lo que debemos ignorar a aquellos con la If Blank then Blank else Mathlógica.

Si todo estuviera en una celda, la solución sería 95 bytes:

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.