Знайдіть перехресний продукт


20

Перехресне твір двох тривимірних векторів і це єдиний вектор таким чином, що:abc

  • c є ортогональним і для іab

  • Величина дорівнює площі паралелограма, утвореного іcaб

  • Напрямки , , і , в такому порядку, слідувати правилу правої руки .abc

Існує кілька еквівалентних формул для перехресного продукту, але одна така:

а×б=det[ijка1а2а3б1б2б3]

де i , j , і к - одиничні вектори в першому, другому та третьому вимірах.

Виклик

З огляду на два 3D-вектори, напишіть повну програму або функцію, щоб знайти їх перехресний продукт. Вбудовані, які конкретно розраховують поперечний продукт, заборонені.

Вхідні дані

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

Вихідні дані

Їх перехресний продукт у розумному форматі з кожним компонентом точним до чотирьох значущих цифр або 10-4 , залежно від того, що є втраченим. Наукові позначення необов’язкові.

Тестові кейси

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

Це , тому найкоротше рішення в байтах виграє.

Малтісен поставив подібний виклик , але відповідь була поганою, і питання не було відредаговано.


Чи можна вхід сприймати як двовимірний масив?
Денніс

Так, поки 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)))

Ласкаво просимо до головоломки програмування та обміну стека коду для гольфу. Це чудова відповідь, +1. Молодці, щоб відповісти мовою, яка не збирається перемагати, але все-таки гольфує навантаження. Найчастіше проблеми з кодовим гольфом стосуються більше мов, ніж між ними!
wizzwizz4

9

Діалог APL, 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]);}

Не збираюсь вигравати жодних призів на тривалість, але подумав, що все-таки поїду.

  • Вхід - це перелік компонентів, що обмежується новим рядком або простором (тобто a1 a2 a3 b1 b2 b3), вихід - з обмеженим простором (тобто c1 c2 c3).
  • Циклічно перестановлює показники двох вхідних векторів для обчислення добутку - потрібно менше символів, ніж виписування визначників!

Демо

Безголівки:

#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
Ласкаво просимо до головоломки програмування та обміну стека коду для гольфу. Це чудова відповідь; добре зроблено для відповіді мовою, яка не переможе мов для гольфу. +1.
wizzwizz4

2
Ваші перші forне потрібні{}
видалено

ура, оновлено.
calvinsykes

1
Ви можете замінити & v [6-i] на v + 6-i. Крім того, ви можете замінити крапку з комою після j = i% 3 і k = (i + 1)% 3 комами, що робить усе після одного для одного оператора, щоб ви могли опустити {}. Нарешті, якщо ви ініціалізуєте i на 1 для другого циклу, ви можете перемістити приріст у 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 байт шляхом перестановки програми, щоб дозволити використовувати негласне визначення замість локальної лямбда. На жаль, це рішення більше не працює в oK, і вимагає офіційного перекладача k5. Треба взяти моє слово за це, поки я не виправлю помилку в oK:

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

Пітон, 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],[у1,у2],[z1,z2]]Z

ṁ4ÆḊƝ

Спробуйте в Інтернеті!

Ось пояснення PDF у випадку, якщо розмітка SE не може впоратися з цим.


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

(х1,у1,z1)v1(х2,у2,z2)v2

v1=х1i+у1j+z1к
v2=х2i+у2j+z2к

Охуz

v1×v2=(х1i+у1j+z1к)×(х2i+у2j+z2к)

i×j=к,i×к=-j,j×i=-к,j×к=i,к×i=j,к×j=-i

Після необхідних перестановок та розрахунків:

v1×v2=(у1z2-z1у2)i+(z1х2-х1z2)j+(х1у2-у1х2)к

Тісний зв’язок з детермінантами матриці

Тут слід зазначити цікаве:

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

||

Пояснення желейного коду

Ну ... не багато тут пояснювати. Він просто генерує матрицю:

(x1y1z1x1 x2y2z2x2)

І для кожної пари сусідніх матриць він обчислює визначник матриці, утвореної приєднанням двох.

ṁ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 байт

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

44 байти, якщо для введення потрібно два масиви:

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

52 байти для більш цікавої версії:

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


0

APL (NARS), 23 символи, 46 байт

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

тест:

  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.