Encontre o produto cruzado

20

O produto cruzado de dois vetores tridimensionais e é o vetor único modo que:abc

  • c é ortogonal a eab

  • A magnitude de é igual à área do paralelogramo formado por ecab

  • As instruções de , e , nessa ordem, seguem a regra da direita .abc

Existem algumas fórmulas equivalentes para produtos cruzados, mas uma é a seguinte:

a×b=det[ijka1a2a3b1b2b3]

onde i , j e k são os vetores de unidade na primeira, segunda e terceira dimensões.

Desafio

Dados dois vetores 3D, escreva um programa ou função completo para encontrar seu produto cruzado. Os componentes internos que calculam especificamente o produto cruzado não são permitidos.

Entrada

Duas matrizes de três números reais cada. Se o seu idioma não tiver matrizes, os números ainda deverão ser agrupados em três. Ambos os vetores terão magnitude <216 . Observe que o produto cruzado não é comutativo ( uma×b=-(b×uma) ), portanto, você deve ter uma maneira de especificar a ordem.

Saída

Seu produto cruzado, em um formato razoável, com cada componente com precisão de quatro algarismos significativos ou 10-4 , o que for mais fraco. A notação científica é opcional.

Casos de teste

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

Isso é , então a solução mais curta em bytes vence.

Maltysen postou um desafio semelhante , mas a resposta foi fraca e a pergunta não foi editada.

lirtosiast
fonte
A entrada pode ser tomada como uma matriz 2D?
Dennis
Sim, desde que 2 seja a dimensão externa.
precisa saber é

Respostas:

14

Geléia, 14 13 12 bytes

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

Experimente online!

Como funciona

;"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).

Versão não concorrente (10 bytes)

OK, isso é embaraçoso, mas a linguagem de manipulação de array Jelly não tinha um built-in para rotação de array até agora. Com este novo built-in, podemos salvar dois bytes adicionais.

ṙ-×
ç_ç@ṙ-

Isso usa a abordagem da resposta J de @ AlexA . Experimente online!

Como funciona

ṙ-×     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).
Dennis
fonte
Converta cada par da base -1? Isso é apenas o mal. +1
ETHproductions
10

LISP, 128 122 bytes

Oi! Este é o meu código:

(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)))

Eu sei que não é a solução mais curta, mas ninguém forneceu uma no Lisp, até agora :)

Copie e cole o seguinte código aqui para experimentá-lo!

(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)))
PieCot
fonte
Bem-vindo à Programação de quebra-cabeças e troca de pilha de código de golfe. Esta é uma ótima resposta, +1. Bem feito por responder em um idioma que não vai ganhar, mas ainda assim jogando muito. Freqüentemente, os desafios do código-golfe envolvem mais idiomas do que entre eles!
precisa saber é o seguinte
9

Dyalog APL, 12 bytes

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

Com base na resposta J de @ AlexA. E (coincidentemente) equivalente à melhoria de @ randomra na seção de comentários dessa resposta.

Experimente online no TryAPL .

Como funciona

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].
Dennis
fonte
9

J, 27 14 bytes

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

Este é um verbo diádico que aceita matrizes à esquerda e à direita e retorna seu produto cruzado.

Explicação:

         *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

Exemplo:

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

Experimente aqui

Economizou 13 bytes graças a randomra!

Alex A.
fonte
@randomra Isso é incrível, obrigado! Como não sou especialista em J, ainda estou descobrindo exatamente como funciona, mas tenho uma ideia geral.
Alex A.
Alguns esclarecimentos: *2&|.é um garfo de dois verbos: *e 2&|.. Multiplica a entrada esquerda por uma rotação de 2 entradas à direita. Esse garfo é armazenado, vportanto, quando escrevemos v~, é equivalente a (*2&|.)~, onde ~trocamos os parâmetros de entrada esquerdo e direito da peça entre parênteses.
randomra 30/01
@ randomra Ok, isso faz sentido. Obrigado novamente!
Alex A.
6

C, 156 154 150 148 144 bytes

#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]);}

Não vou ganhar nenhum prêmio pela duração, mas pensei que eu teria de qualquer maneira.

  • A entrada é uma lista de componentes delimitada por nova linha ou espaço (por exemplo, a1 a2 a3 b1 b2 b3), a saída é delimitada por espaço (por exemplo, c1 c2 c3).
  • Permita ciclicamente os índices dos dois vetores de entrada para calcular o produto - requer menos caracteres do que escrever os determinantes!

Demo

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]);
}
calvinsykes
fonte
1
Bem-vindo à Programação de quebra-cabeças e troca de pilha de código de golfe. Esta é uma ótima resposta; bem feito para responder em um idioma que não supera os idiomas do golfe. +1.
precisa saber é o seguinte
2
O seu primeiro fornão precisa{}
removido
Saúde, atualizado.
precisa saber é o seguinte
1
Você pode substituir & v [6-i] por v + 6-i. Além disso, você pode substituir o ponto-e-vírgula após j = i% 3 ek = (i + 1)% 3 por vírgulas, o que faz com que tudo apareça após uma única instrução, para que você possa omitir o {}. Por fim, se você inicializar i para 1 para o segundo loop for, poderá mover o incremento para k = ++ i% 3, salvando alguns colchetes. Se você não está preocupado com avisos e usa a versão correta do C, também pode pular a inclusão.
Alchymist
incrível, felicidades! Meu compilador não aceita a omissão do cabeçalho, por isso fiquei com uma versão que sou capaz de construir.
Calvinsykes
4

Haskell, 41 bytes

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

Uma solução simples.

xnor
fonte
4

Bash + coreutils, 51

eval set {$1}*{$2}
bc<<<"scale=4;$6-$8;$7-$3;$2-$4"
  • A linha 1 constrói uma expansão de braquete que fornece o produto cartesiano dos dois vetores e os define nos parâmetros posicionais.
  • A linha 2 subtrai os termos apropriados; bcfaz a avaliação aritmética com a precisão necessária.

A entrada é como duas listas separadas por vírgula na linha de comando. Saída como linhas separadas por nova linha:

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

MATL , 17 bytes

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

A primeira entrada é a , a segunda é b .

Experimente online!

Explicação

!              % 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
Luis Mendo
fonte
4

Pitão, 16 bytes

-VF*VM.<VLQ_BMS2

Experimente online: Demonstração

Explicação:

-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
Jakube
fonte
3

K5, 44 40 37 32 bytes

Escreveu este há muito tempo e espanou-o novamente recentemente .

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

Em ação:

 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

Editar 1:

Salva 4 bytes, inserindo a entrada como uma lista de listas em vez de dois argumentos separados:

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

Edição 2:

Economizou 3 bytes calculando uma tabela de pesquisa com decodificação básica:

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}

Edição 3:

Salve 5 bytes reorganizando o aplicativo para permitir o uso de uma definição tácita em vez de uma lambda local. Infelizmente, esta solução não funciona mais em OK e requer o intérprete oficial do k5. Vou ter que acreditar na minha palavra até que eu corrija o erro em 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}
JohnE
fonte
3

Ruby , 49 bytes

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

Experimente online!

Retornando após 2 anos, retirei 12 bytes usando como Ruby trata índices de matriz negativos. -1é o último elemento da matriz, -2o segundo último etc.

Ruby, 57

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

No programa de teste

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]]
Level River St
fonte
2

Python, 73 48 bytes

Obrigado @FryAmTheEggman

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

Isso se baseia na definição de componente do produto cruzado de vetor.

Experimente aqui

TanMath
fonte
lambda (a,b,c),(d,e,f):...deve economizar muito.
FryAmTheEggman
@FryAmTheEggman Você está certo. Esqueci que o lambda pode especificar como o argumento deve ser.
precisa saber é o seguinte
2

Gelatina , 5 bytes

[[x1,x2],[y1,y2],[z1,z2]]Z

ṁ4ÆḊƝ

Experimente online!

Aqui está uma explicação em PDF , caso a remarcação SE não consiga lidar com isso.


O produto cruzado na forma analítica

(x1,y1,z1)v1(x2,y2,z2)v2

v1=x1Eu+y1j+z1k
v2=x2Eu+y2j+z2k

Oxyz

v1×v2=(x1Eu+y1j+z1k)×(x2Eu+y2j+z2k)

Eu×j=k,Eu×k=-j,j×Eu=-k,j×k=Eu,k×Eu=j,k×j=-Eu

Após os rearranjos e cálculos necessários:

v1×v2=(y1z2-z1y2)Eu+(z1x2-x1z2)j+(x1y2-y1x2)k

A estreita relação com os determinantes da matriz

Há uma coisa interessante a ser observada aqui:

x1y2-y1x2=|x1y1 x2y2|
z1x2-x1z2=|z1x1 z2x2|
y1z2-z1y2=|y1z1 y2z2|

||

Explicação do código de geléia

Bem ... não há muito a explicar aqui. Apenas gera a matriz:

(x1y1z1x1 x2y2z2x2)

E para cada par de matrizes vizinhas, calcula o determinante da matriz formada pela união das duas.

ṁ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.
Mr. Xcoder
fonte
1

ES6, 40 bytes

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

44 bytes se a entrada precisar ser de duas matrizes:

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

52 bytes para uma versão mais interessante:

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

Julia 0,7 , 45 39 bytes

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

Experimente online!

Usa a fórmula baseada em determinante fornecida na descrição da tarefa.

Graças a H.PWiz por -6 bytes.

Kirill L.
fonte
39 bytes com dois truques:f(a,b)=1:3 .|>i->det([eye(3)[i,:] a b])
H.PWiz
0

APL (NARS), 23 caracteres, 46 bytes

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

teste:

  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 
RosLuP
fonte