Нормализовать вектор

28

Чтобы нормализовать вектор, нужно масштабировать его до длины 1 ( единичный вектор ), сохраняя при этом постоянное направление.

Например, если мы хотим , чтобы нормализовать вектор с 3 -х компонентов, U , мы бы сначала найти его длину:

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

... и затем масштабируйте каждый компонент на это значение, чтобы получить вектор длины 1.

û = u ÷ | u |


Соревнование

Ваша задача - написать программу или функцию, которая, учитывая непустой список целых чисел со знаком, интерпретирует их как вектор и нормализует их. Это должно работать для любого числа измерений, например (контрольные примеры, округленные до двух десятичных разрядов):

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

Правила:

  • Вы можете предположить, что список ввода будет:
    • Иметь хотя бы один ненулевой элемент
    • Содержать только числа в пределах стандартного диапазона с плавающей запятой вашего языка
  • Ваш вывод должен быть с точностью не менее двух знаков после запятой . Возврат фракций / символьных значений «бесконечной точности» также разрешен, если ваш язык хранит данные внутри себя.
  • Представления должны быть либо полной программой, которая выполняет ввод / вывод, либо функцией. Представления функций могут либо вернуть новый список, либо изменить данный список на месте.
  • Встроенные векторные функции / классы разрешены. Кроме того, если ваш язык имеет векторный тип, который поддерживает произвольное количество измерений, вы можете использовать одно из них в качестве входных данных.

Это соревнование по , поэтому вы должны стремиться к достижению как можно более короткого решения (в байтах).

FlipTack
источник
Должно ли оно иметь как минимум два десятичных знака для каждого возможного ввода (что невозможно для любого стандартного типа значений с плавающей запятой) или только для предоставленных вами примеров? Например, ответ Steadybox обеспечивает 2 десятичных знака точности для всего вашего теста, но он использует целые числа для суммы квадратов, что, конечно, не подходит почти для всех входных данных (например, [0,1, 0,1]).
Кристоф
... теперь мы просто ждем lang со встроенной функцией нормы, сопоставленной с одним
символом
Должно быть не менее 2dp для каждого возможного ввода @Christoph
FlipTack
@FlipTack, но это исключает в основном все языки, потому что точки с плавающей запятой имеют большие показатели, чем мантисса, что означает, что они не всегда имеют достаточную точность, чтобы иметь какие-либо десятичные разряды.
Кристоф
Почему 6 в 4-м примере и -6 в 5-м соответственно не нормализуются до 1 и -1?
Мачта

Ответы:

15

05AB1E , 4 байта

Код:

nOt/

Попробуйте онлайн!

объяснение

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
п0Т что я ожидал /
СМУ
10

JavaScript (ES6), 31 байт

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

Контрольные примеры

Arnauld
источник
9

J , 8 байт

%+/&.:*:

Попробуйте онлайн!

6 байт %|@j./работает, если вектор хотя бы 2-мерен .

FrownyFrog
источник
Люблю способ получения величины.
Коул
1
@cole на 1 байт длиннее:%1%:@#.*:
FrownyFrog
6
Не могли бы вы добавить объяснение непосвященному в J?
МечМК1
% (делить на) + / (сумма) & .: (под) *: (квадрат). + суммирует две вещи. + / суммирует список вещей. & .: изменяет предыдущую операцию, применяя сначала следующую операцию, а затем обратную. % обычно принимает два аргумента, но (% f) является функцией от x до x% (fx). Большинство операторов автоматически работают со списками.
Роман Одайский
И по тем же принципам функция, которая «нормализует» вектор, добавляя к каждому компоненту такое число, которое они суммируют до нуля, это «- + /% #».
Роман Одайский
8

Желе , 5 3 байта

÷ÆḊ

Попробуйте онлайн! или посмотрите набор тестов

Сохранено 2 байта благодаря милям!

Caird Coneheringaahing
источник
3 байта с÷ÆḊ
мили
@ Майлз Да, никогда не знал об этом встроенном. Спасибо
caird coinheringaahing
к сожалению, эта встроенная функция дает + ve мод для скаляров на примерное абсолютное значение TIO .. проблема требует сохранения знака
jayprich
6

C  73  70 байт

Спасибо @Christoph за сохранение байта!

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

Попробуйте онлайн!

Steadybox
источник
+1. s=0,i=0вместо одного s=i=0спасает
xanoetux
Я люблю использование, s[-i]но, к сожалению, *--v/=sqrt(s);на 1 байт короче.
Кристоф
1
@xanoetux Спасибо, но мне нужно инициализировать переменные внутри функции, потому что функции нужно многократно использовать . Кроме того, как глобальные переменные, sи iавтоматически инициализируются в 0. (Оказывается, мне не нужно инициализировать iв функции, потому что функция всегда оставляет ее в значении 0)
Steadybox
1
@ Кристоф Спасибо! Сначала я печатал значения из функции, поэтому мне нужно v[-i]было получить значения в правильном порядке.
Steadybox
3

CJam , 9 байт

{_:mhzf/}

Попробуйте онлайн!

объяснение

_    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 байтов

Ans/√(sum(Ans2

Запустите с {1,2,3}:prgmNAME, где {1,2,3}вектор, который будет нормализован.

Делит каждый элемент в векторе на квадратный корень из суммы квадратов его элементов.

pizzapants184
источник
Мы получили тот же ответ!
kamoroso94
@ kamoroso94 Ой! Не видел твоего, когда я это опубликовал. Если вы хотите добавить объяснение этого к своему ответу, я удалю это.
pizzapants184
Нет я просто уберу свою Вы приложили больше усилий к своему ответу: P
kamoroso94
3

R , 23 байта

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

Попробуйте онлайн!

v%*%vвычисляет скалярное произведение v с самим собой.
Функция выдаст предупреждение для векторов длиной 2 или более.

Giuseppe
источник
2

MATL , 5 байтов

t2&|/

Попробуйте онлайн!

Я не совсем уверен, что это самый короткий способ сделать это. Сначала мы дублируем ввод, затем выбираем второй тип вывода |(который либо abs, normлибо determinant). Наконец, мы делим входные данные на норму.

Альтернатива для 7 байтов:

t2^sX^/
Стьюи Гриффин
источник
2

C ++ (gcc), 70 байт

Вход по std::valarray<float>. Перезаписывает оригинальный вектор.

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

Попробуйте онлайн!

Колера Су
источник
Я просто время от времени прячу Codegolf, но разве это недопустимый C ++, учитывая "#import", который является специфическим расширением Microsoft?
Френель
@phresnel #importработает как минимум с GCC, Clang и MinGW. Но да, это не стандартный C ++.
Steadybox
@phresnel Я забыл указать GCC. Исправлена.
Колера Су
2

APL (Dyalog) , 13 12 10 байтов

1 байт сохранен благодаря @ Adám

2 байта сохранены благодаря @ngn

⊢÷.5*⍨+.×⍨

Попробуйте онлайн!

Как?

  ÷  .5*⍨  +.  ×⍨
u  ÷       Σ   u²
Уриэль
источник
Тренируйтесь меньше:⊢÷.5*⍨(+/×⍨)
Адам
@ Adám большое спасибо! Я пытался часами, не мог заставить поезд работать
Уриэль
Мы должны что-то с этим сделать, так как это действительно не так сложно. Если у вас есть монадическая функция (кроме самой правой), начинайте скобки слева от нее (или используйте, если она не является производной). Кроме этого, просто поменяйте местами и на и : {⍵÷.5*⍨+/×⍨⍵}{⍵÷.5*⍨(+/(×⍨⍵))}⊢÷.5*⍨(+/(×⍨⊢))⊢÷.5*⍨(+/(×⍨))⊢÷.5*⍨(+/×⍨)
Adám
(+/×⍨)->+.×⍨
нгн
1

C # (.NET Core) , 51 + 64 = 115 байт

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

Попробуйте онлайн!

+64 байта для using System;using System.Collections.Generic;using System.Linq;

C # (.NET Core) , 94 + 13 = 107 байт

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

Попробуйте онлайн!

+13 байт для using System;

Не Линк подход

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
источник
1

Пип , 10 байт

9 байтов кода, +1 для -pфлага.

g/RT$+g*g

Принимает вектор как отдельные аргументы командной строки. Попробуйте онлайн!

Как это работает

      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
источник
1

Pyth, 5 байт

cR.aQ

Попробуйте онлайн: Test Suite

Объяснение:

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
источник
1

Perl 6 , 25 байт

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

Попробуйте онлайн!

$_аргумент списка функции, делится »/»по элементам ( »²) на квадратный корень из суммы квадратов элементов ( ).

Шон
источник
1

Рубин, 39 35 байт

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

-4 байта благодаря G B.

м-chrzan
источник
1
Сохраните несколько байтов, используя sum{...}вместоmap{...}.sum
GB
0

APL NARS 12 персонажей

f←{⍵÷√+/⍵*2}
RosLuP
источник
Вам не нужно считать количество f← байтов, так как вы можете использовать dfns без него. Кстати, это один байт в NARS? Я не знаком с этим, поэтому просто спрашиваю
Уриэль
@Uriel Nars Apl из немногих, кого я знаю, будет писать с Unicode, поэтому число байтов должно быть 12x2
RosLuP
0

Google Sheets, 65 байт

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

Список ввода находится в столбце Aс одной записью на ячейку. Так электронные таблицы обычно используют списки. К сожалению, это обычно приводит к длинному списку ,0,0,0,0,0,....в конце, поэтому мы должны игнорировать тех, кто с If Blank then Blank else Mathлогикой.

Если бы все было в одной ячейке, вместо этого было бы 95 байтов:

=ArrayFormula(TextJoin(",",1,If(Split(A1,",")="","",Split(A1,",")/Sqrt(Sumsq(Split(A1,","))))))
Инженер Тост
источник
0

Swift 4, 44 байта

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

Пересчитывает векторную норму для каждого компонента, но, по крайней мере, это кратко!

Александр - Восстановить Монику
источник