Найти продукт креста


20

Перекрестное произведение двух трехмерных векторов a и b это единственный вектор c таким образом, что:

  • c ортогональна обоимa иb

  • Величина c равна площади параллелограмма, образованной a и b

  • Направления a , b и c в указанном порядке следуют правилу правой руки .

Существует несколько эквивалентных формул для перекрестного произведения, но одна из них выглядит следующим образом:

a×b=det[ijka1a2a3b1b2b3]

где i , j и k - единичные векторы в первом, втором и третьем измерениях.

Вызов

Учитывая два трехмерных вектора, напишите полную программу или функцию, чтобы найти их перекрестное произведение. Встроенные функции, которые специально рассчитывают перекрестное произведение, запрещены.

вход

Два массива по три вещественных числа в каждом. Если у вашего языка нет массивов, числа все равно должны быть сгруппированы в тройки. Оба вектора будут иметь величину <216 . Обратите внимание, что перекрестное произведение некоммутативно ( a×b=(b×a) ), поэтому у вас должен быть способ указать порядок.

Выход

Их перекрестное произведение в разумном формате, каждый компонент с точностью до четырех значащих цифр или 104 , в зависимости от того, что меньше. Научная запись не является обязательной.

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

[3, 1, 4], [1, 5, 9]
[-11, -23, 14]

[5, 0, -3], [-3, -2, -8]
[-6, 49, -10]

[0.95972, 0.25833, 0.22140],[0.93507, -0.80917, -0.99177]
[-0.077054, 1.158846, -1.018133]

[1024.28, -2316.39, 2567.14], [-2290.77, 1941.87, 712.09]
[-6.6345e+06, -6.6101e+06, -3.3173e+06]

Это , поэтому выигрывает самое короткое решение в байтах.

Maltysen отправил аналогичный вызов , но ответ был плохим, и вопрос не был отредактирован.


Можно ли использовать входные данные как двумерный массив?
Деннис

Да, пока 2 - это внешнее измерение.
lirtosiast

Ответы:


14

Желе, 14 13 12 байт

;"s€2U×¥/ḅ-U

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

Как это устроено

;"s€2U×¥/ḅ-U Main link. Input: [a1, a2, a3], [b1, b2, b3]

;"           Concatenate each [x1, x2, x3] with itself.
             Yields [a1, a2, a3, a1, a2, a3], [b1, b2, b3, b1, b2, b3].
  s€2        Split each array into pairs.
             Yields [[a1, a2], [a3, a1], [a2, a3]], [[b1, b2], [b3, b1], [b2, b3]].
       ¥     Define a dyadic chain:
     U         Reverse the order of all arrays in the left argument.
      ×        Multiply both arguments, element by element.
        /    Reduce the 2D array of pairs by this chain.
             Reversing yields [a2, a1], [a1, a3], [a3, a2].
             Reducing yields [a2b1, a1b2], [a1b3, a3b1], [a3b2, a2b3].
         ḅ-  Convert each pair from base -1 to integer.
             This yields [a1b2 - a2b1, a3b1 - a1b3, a2b3 - a3b2]
           U Reverse the array.
             This yields [a2b3 - a3b2, a3b1 - a1b3, a1b2 - a2b1] (cross product).

Неконкурентная версия (10 байт)

Хорошо, это неудобно, но в языке манипулирования массивами Jelly до сих пор не было встроенной функции вращения массива. С помощью этого нового встроенного мы можем сохранить два дополнительных байта.

ṙ-×
ç_ç@ṙ-

Это использует подход из ответа J AlexA . Попробуйте онлайн!

Как это устроено

ṙ-×     Helper link. Left input: x = [x1, x2, x3]. Right input: y = [y1, y2, y3].

ṙ-      Rotate x 1 unit to the right (actually, -1 units to the left).
        This yields [x3, x1, x2].
  ×     Multiply the result with y.
        This yields [x3y1, x1y2, x2y3].


ç_ç@ṙ-  Main link. Left input: a = [a1, a2, a3]. Right input: b = [b1, b2, b3].

ç       Call the helper link with arguments a and b.
        This yields [a3b1, a1b2, a2b3].
  ç@    Call the helper link with arguments b and a.
        This yields [b3a1, b1a2, b2a3].
_       Subtract the result to the right from the result to the left.
        This yields [a3b1 - a1b3, a1b2 - a2b1, a2b3 - a3b2].
    ṙ-  Rotate the result 1 unit to the right.
        This yields [a2b3 - a3b2, a3b1 - a1b3, a1b2 - a2b1] (cross product).

Конвертировать каждую пару из базы -1? Это просто зло. +1
ETHproductions

10

LISP, 128 122 байта

Здравствуй! Это мой код:

(defmacro D(x y)`(list(*(cadr,x)(caddr,y))(*(caddr,x)(car,y))(*(car,x)(cadr,y))))(defun c(a b)(mapcar #'- (D a b)(D b a)))

Я знаю, что это не самое короткое решение, но никто не предоставил его в Лиспе до сих пор :)

Скопируйте и вставьте следующий код здесь, чтобы попробовать это!

(defmacro D(x y)`(list(*(cadr,x)(caddr,y))(*(caddr,x)(car,y))(*(car,x)(cadr,y))))(defun c(a b)(mapcar #'- (D a b)(D b a)))

(format T "Inputs: (3 1 4), (1 5 9)~%")
(format T "Result ~S~%~%" (c '(3 1 4) '(1 5 9)))

(format T "Inputs: (5 0 -3), (-3 -2 -8)~%")
(format T "Result ~S~%~%" (c '(5 0 -3) '(-3 -2 -8)))

(format T "Inputs: (0.95972 0.25833 0.22140), (0.93507 -0.80917 -0.99177)~%")
(format T "Result ~S~%" (c '(0.95972 0.25833 0.22140) '(0.93507 -0.80917 -0.99177)))

(format T "Inputs: (1024.28 -2316.39 2567.14), (-2290.77 1941.87 712.09)~%")
(format T "Result ~S~%" (c '(1024.28 -2316.39 2567.14) '(-2290.77 1941.87 712.09)))

Добро пожаловать в Программирование Пазлов и Code Golf Stack Exchange. Это отличный ответ, +1. Хорошо сделано для того, чтобы ответить на языке, который не выиграет, но все еще играет в гольф. Нередко проблемы кода-гольфа связаны скорее с языками, чем между ними!
wizzwizz4

9

Дьялог АПЛ, 12 байт

2⌽p⍨-p←⊣×2⌽⊢

На основе J-ответа @ AlexA. И (по совпадению) эквивалентно улучшению @ randomra в разделе комментариев к этому ответу.

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

Как это устроено

2⌽p⍨-p←⊣×2⌽⊢  Dyadic function.
              Left argument: a = [a1, a2, a3]. Right argument: b = [b1, b2, b3].

         2⌽⊢  Rotate b 2 units to the left. Yields [b3, b1, b2].
       ⊣×     Multiply the result by a. Yields [a1b3, a2b1, a3b2].
     p←       Save the tacit function to the right (NOT the result) in p.
  p⍨          Apply p to b and a (reversed). Yields [b1a3, b2a1, b3a2].
    -         Subtract the right result (p) from the left one (p⍨).
              This yields [a3b1 - a1b3, a1b2 - a2b1, a2b3 - a3b2].
2⌽            Rotate the result 2 units to the left.
              This yields [a2b3 - a3b2, a3b1 - a1b3, a1b2 - a2b1].

9

J, 27 14 байт

2|.v~-v=.*2&|.

Это двоичный глагол, который принимает массивы слева и справа и возвращает их перекрестное произведение.

Объяснение:

         *2&|.     NB. Dyadic verb: Left input * twice-rotated right input
      v=.          NB. Locally assign to v
   v~-             NB. Commute arguments, negate left
2|.                NB. Left rotate twice

Пример:

    f =: 2|.v~-v=.*2&|.
    3 1 4 f 1 5 9
_11 _23 14

Попробуй здесь

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


@randomra Это круто, спасибо! Я не эксперт J, поэтому я все еще выясняю, как именно это работает, но у меня есть общее представление.
Алекс А.

Некоторые уточнения: *2&|.это вилка из двух глаголов: *а 2&|.. Он умножает левый вход на повернутый на 2 правый вход. Эта ветвь хранится в том, vчто когда мы пишем v~, она эквивалентна (*2&|.)~, где ~меняются местами левый и правый входные параметры для заключенной в скобки части.
randomra

@randomra Хорошо, это имеет смысл. Еще раз спасибо!
Алекс А.

6

C 156 154 150 148 144 байта

#include <stdio.h>
main(){float v[6];int i=7,j,k;for(;--i;)scanf("%f",v+6-i);for(i=1;i<4;)j=i%3,k=++i%3,printf("%f ",v[j]*v[k+3]-v[k]*v[j+3]);}

Не собираюсь выигрывать какие-либо призы за длину, но все равно думал, что мне пора.

  • Input представляет собой список компонентов, разделенных новой строкой или пробелом (т.е. a1 a2 a3 b1 b2 b3), вывод - пробел с разделителями (т.е. c1 c2 c3).
  • Циклически переставляет индексы двух входных векторов для вычисления продукта - требуется меньше символов, чем записывается определитель!

демонстрация

Ungolfed:

#include <cstdio>
int main()
{
    float v[6];
    int i = 7, j, k;
    for (; --i; ) scanf("%f", v + 6 - 1);
    for (i = 1; i < 4; )
        j = i % 3,
        k = ++i % 3,
        printf("%f ", v[j] * v[k + 3] - v[k] * v[j + 3]);
}

1
Добро пожаловать в Программирование Пазлов и Code Golf Stack Exchange. Это отличный ответ; хорошо сделанный для ответа на языке, который не побьет языки гольфа. +1.
wizzwizz4

2
Ваша первая forне нужна{}
удалено

ура, обновлено.
Calvinsykes

1
Вы можете заменить & v [6-i] на v + 6-i. Кроме того, вы можете заменить точку с запятой после j = i% 3 и k = (i + 1)% 3 запятыми, что делает все после символа for для одного оператора, поэтому вы можете опустить {}. Наконец, если вы инициализируете i в 1 для второго цикла for, вы можете переместить приращение в k = ++ i% 3, сохранив пару скобок. Если вы не беспокоитесь о предупреждениях и используете правильную версию C, вы можете также пропустить включение.
Алхимик

офигенно, ура! Мой компилятор не смирится с отсутствием заголовка, поэтому я остановился на версии, которую смог создать.
Calvinsykes

4

Haskell, 41 байт

x(a,b,c)(d,e,f)=(b*f-c*e,c*d-a*f,a*e-b*d)

Простое решение.


4

Bash + coreutils, 51

eval set {$1}*{$2}
bc<<<"scale=4;$6-$8;$7-$3;$2-$4"
  • Линия 1 строит разложение скобок, которое дает декартово произведение двух векторов и устанавливает их в позиционные параметры.
  • Строка 2 вычитает соответствующие термины; bcвыполняет арифметическую оценку с необходимой точностью.

Ввод в виде двух разделенных запятыми списков в командной строке. Вывести в виде строк, разделенных новой строкой:

$ ./crossprod.sh 0.95972,0.25833,0.22140 0.93507,-0.80917,-0.99177
-.07705
1.15884
-1.01812
$

4

MATL , 17 байт

!*[6,7,2;8,3,4])d

Первый вход a , второй b .

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

объяснение

!              % input b as a row array and transpose into a column array
*              % input a as a row array. Compute 3x3 matrix of pairwise products
[6,7,2;8,3,4]  % 2x3 matrix that picks elements from the former in column-major order
)              % apply index
d              % difference within each column

4

Pyth, 16 байт

-VF*VM.<VLQ_BMS2

Попробуйте онлайн: демонстрация

Объяснение:

-VF*VM.<VLQ_BMS2   Q = input, pair of vectors [u, v]
              S2   creates the list [1, 2]
           _BM     transforms it to [[1, -1], [2, -2]]
      .<VLQ        rotate of the input vectors accordingly to the left:
                   [[u by 1, v by -1], [u by 2, v by -2]]
   *VM             vectorized multiplication for each of the vector-pairs
-VF                vectorized subtraction of the resulting two vectors

3

K5, 44 40 37 32 байта

Написал это довольно давно и недавно отряхнул .

{{x[y]-x[|y]}[*/x@']'3 3\'5 6 1}

В бою:

 cross: {{x[y]-x[|y]}[*/x@']'3 3\'5 6 1};

 cross (3 1 4;1 5 9)
-11 -23 14
 cross (0.95972 0.25833 0.22140;0.93507 -0.80917 -0.99177)
-7.705371e-2 1.158846 -1.018133

Изменить 1:

Сохранено 4 байта, взяв входные данные в виде списка списков вместо двух отдельных аргументов:

old: {m:{*/x@'y}(x;y);{m[x]-m[|x]}'(1 2;2 0;0 1)}
new: {m:{*/x@'y}x    ;{m[x]-m[|x]}'(1 2;2 0;0 1)}

Изменить 2:

Сохранено 3 байта путем вычисления таблицы поиска с базовым декодированием:

old: {m:{*/x@'y}x;{m[x]-m[|x]}'(1 2;2 0;0 1)}
new: {m:{*/x@'y}x;{m[x]-m[|x]}'3 3\'5 6 1}

Изменить 3:

Сохраните 5 байтов, переставив приложение, чтобы разрешить использование молчаливого определения вместо локальной лямбды. К сожалению, это решение больше не работает в ОК и требует официального переводчика k5. Должен поверить мне на слово, пока я не исправлю ошибку в ОК:

old: {m:{*/x@'y}x;{m[x]-m[|x]}'3 3\'5 6 1}
new: {{x[y]-x[|y]}[*/x@']     '3 3\'5 6 1}

3

Рубин , 49 байтов

->u,v{(0..2).map{|a|u[a-2]*v[a-1]-u[a-1]*v[a-2]}}

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

Вернувшись через 2 года, я сбрил 12 байтов, используя то, как Ruby обрабатывает отрицательные индексы массивов. -1последний элемент массива, -2второй последний и т. д.

Руби, 57

->u,v{(0..2).map{|a|u[b=(a+1)%3]*v[c=(a+2)%3]-u[c]*v[b]}}

В тестовой программе

f=->u,v{(0..2).map{|a|u[b=(a+1)%3]*v[c=(a+2)%3]-u[c]*v[b]}}

p f[[3, 1, 4], [1, 5, 9]]

p f[[5, 0, -3], [-3, -2, -8]]

p f[[0.95972, 0.25833, 0.22140],[0.93507, -0.80917, -0.99177]]

p f[[1024.28, -2316.39, 2567.14], [-2290.77, 1941.87, 712.09]]

2

Python, 73 48 байт

Спасибо @FryAmTheEggman

lambda (a,b,c),(d,e,f):[b*f-c*e,c*d-a*f,a*e-b*d]

Это основано на определении компонента векторного перекрестного произведения.

Попробуй здесь


lambda (a,b,c),(d,e,f):...должен сэкономить много.
FryAmTheEggman

@FryAmTheEggman Вы правы. Я забыл, что лямбда может указать, каким должен быть аргумент.
TanMath

2

Желе , 5 байт

Принимает вход в виде [[Икс1,Икс2],[Y1,Y2],[Z1,Z2]], Если вы хотите, чтобы они представляли собой два списка координат XYZ, просто перейдите Zк началу программы.

ṁ4ÆḊƝ

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

Вот объяснение в формате PDF на случай, если SE markdown не может с этим справиться.


Перекрестный продукт в аналитической форме

Позволять (Икс1,Y1,Z1) быть координатами v1 и (Икс2,Y2,Z2) быть координатами v2, Их аналитические выражения следующие:

v1знак равноИкс1я+Y1J+Z1К
v2знак равноИкс2я+Y2J+Z2К

Единственное, что осталось сделать сейчас, это также написать их перекрестный продукт с точки зрения его координат в ОИксYZ Космос.

v1×v2=(x1i+y1j+z1k)×(x2i+y2j+z2k)

Keeping in mind that:

i×j=k,i×k=j,j×i=k,j×k=i,k×i=j,k×j=i

After the necessary rearrangements and calculations:

v1×v2=(y1z2z1y2)i+(z1x2x1z2)j+(x1y2y1x2)k

The close relationship with matrix determinants

There's an interesting thing to note here:

x1y2y1x2=|x1y1 x2y2|
z1x2x1z2=|z1x1 z2x2|
y1z2z1y2=|y1z1 y2z2|

Where we use the notation || for matrix determinant. Notice the beautiful rotational symmetry?

Jelly code explanation

Well... not much to explain here. It just generates the matrix:

(x1y1z1x1 x2y2z2x2)

And for each pair of neighbouring matrices, it computes the determinant of the matrix formed by joining the two.

ṁ4ÆḊƝ – Monadic Link. Takes input as [[x1,x2],[y1,y2],[z1,z2]].
ṁ4    – Mold 4. Cycle the list up to length 4, reusing the elements if necessary.
        Generates [[x1,x2],[y1,y2],[z1,z2],[x1,x2]].
    Ɲ – For each pair of neighbours: [[x1,x2],[y1,y2]], [[y1,y2],[z1,z2]], [[z1,z2],[x1,x2]].
  ÆḊ  – Compute the determinant of those 2 paired together into a single matrix.



1

ES6, 40 bytes

(a,b,c,d,e,f)=>[b*f-c*e,c*d-a*f,a*e-b*d]

44 bytes if the input needs to be two arrays:

([a,b,c],[d,e,f])=>[b*f-c*e,c*d-a*f,a*e-b*d]

52 bytes for a more interesting version:

(a,b)=>a.map((_,i)=>a[x=++i%3]*b[y=++i%3]-a[y]*b[x])

1

Julia 0.7, 45 39 bytes

f(a,b)=1:3 .|>i->det([eye(3)[i,:] a b])

Try it online!

Uses the determinant-based formula given in the task description.

Thanks to H.PWiz for -6 bytes.


39 bytes with two tricks: f(a,b)=1:3 .|>i->det([eye(3)[i,:] a b])
H.PWiz

0

APL(NARS), 23 chars, 46 bytes

{((1⌽⍺)×5⌽⍵)-(5⌽⍺)×1⌽⍵}

test:

  f←{((1⌽⍺)×5⌽⍵)-(5⌽⍺)×1⌽⍵}
  (3 1 4) f (1 5 9)
¯11 ¯23 14 
  (5 0 ¯3) f (¯3 ¯2 ¯8)
¯6 49 ¯10 
  (0.95972 0.25833 0.22140) f (0.93507 ¯0.80917 ¯0.99177)
¯0.0770537061 1.158846002 ¯1.018133265 
  (1024.28 ¯2316.39 2567.14) f (¯2290.77 1941.87 712.09)
¯6634530.307 ¯6610106.843 ¯3317298.117 

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.