Operazioni vettoriali: vec1.dot (vec2) vs vec1 * vec2 vs punto (vec1, vec2) [chiuso]

-2

Qual è il tuo modo preferito per implementare / utilizzare le operazioni sui vettori?

  • vec1.dot (vec2)
    • consente di riutilizzare vec1 ma è difficile da leggere per equazioni più lunghe
  • punto (vec1, vec2)
    • Un mio amico preferisce questo come "punto" non è una proprietà del vettore
  • vec1 * vec2
    • probabilmente sembra il migliore, ma non è possibile in tutte le lingue (ad es. Java)
posta Mene 13.04.2011 - 15:22
fonte

7 risposte

4

Gli operatori sovraccaricati possono essere buoni, ma solo se gli operatori ridefiniti si comportano in modo simile agli originali. Poiché ci sono due prodotti comuni per i vettori (punto e croce), ciò può causare problemi. (Considererei operator*() per punto e operator% per croce, ma non l'ho mai visto in pratica.)

Il prodotto punto si riferisce a entrambi i vettori allo stesso modo, quindi non vorrei usare la prima versione. Sembra troppo come vec2 applicato a vec1 in qualche modo.

Pertanto, preferirei usare dot(vec1, vec2) . Sembra simmetrico come è, e non rende l'interfaccia della classe vettoriale più grande. Più cose impacchettate in una classe ( cough std:string cough ), più è complicato e più possibilità ci sono che qualcosa vada storto da qualche parte.

    
risposta data 13.04.2011 - 16:01
fonte
2

Anche se questa non è una base per una buona domanda soggettiva, vorrei evitare il terzo esempio

vec1 * vec2

poiché la moltiplicazione è diversa da una funzione punto . Ciò potrebbe facilmente causare confusione dalla possibilità (intuitiva soggettiva) di sovraccaricare il carattere '*'.

    
risposta data 13.04.2011 - 15:38
fonte
2

Supponendo C ++, vorrei andare con la tua seconda opzione.

L'ultima opzione è la mia preferita least , ma aggiunge confusione: cosa significa * ? Prodotto a punti o prodotto incrociato? Soprattutto se crei una moltiplicazione scalare di vec * scalar (che anch'io eviterei, personalmente), allora diventa ancora più confusa.

Quindi è solo tra la prima e la seconda opzione quindi. Se leggi l'articolo di Herb Sutter, Monoliths "Unstrung" , entra nel dettaglio dei motivi per cui i non membri non le funzioni di amicizia rendono un'interfaccia migliore delle funzioni membro, quindi non ripeterò tutto ciò che dice, tranne che per dire che sono d'accordo con gran parte di esso.

    
risposta data 13.04.2011 - 15:52
fonte
1

dipende dalla lingua, ad esempio in haskell puoi fare qualcosa di simile a

v1 'dot' v2

Mentre in Javascript probabilmente farei qualcosa di simile

v1.dot(v2);

o forse

Vector.dot(v1, v2);

In lisp / scheme sarebbe

(dot v1 v2)
    
risposta data 13.04.2011 - 16:32
fonte
0

Nel primo esempio, sembra che si stia applicando un'operazione a un vettore, ma poiché un vettore non può essere convertito in uno scalare, l'operazione restituisce un valore e non modifica l'oggetto originale. Quindi forse dot dovrebbe essere un metodo statico nella classe Vector . Questo dà qualcosa di simile al secondo esempio:

Vector.dotProduct(v1, v2);
    
risposta data 13.04.2011 - 15:45
fonte
0

Tutti sono validi, è una questione di gusti e le opzioni fornite dal linguaggio di implementazione.

In una lingua non funzionale, probabilmente utilizzerei la prima opzione. Sì, "punto" non è strettamente una proprietà del vettore, ma può essere applicato solo al vettore. In un'applicazione molto classificata, avere un sacco di funzioni globali in giro può rendere le cose complicate e, a meno che i tuoi sviluppatori non siano tutti ben consapevoli delle diverse funzioni, possono implementare qualcosa di loro. Avere come metodo sull'oggetto vettoriale rende meno probabile che ciò accada.

La seconda opzione è il genere di cosa che farei se lavorassi con un linguaggio funzionale. Non so davvero come spiegarlo, ma sembra proprio che si adatterebbe meglio. Sebbene tu possa sovraccaricare l'operatore di moltiplicazione, la digitazione debole nella maggior parte dei linguaggi funzionali renderebbe questo imbarazzante, penso.

Solo i miei $ 0.02

    
risposta data 13.04.2011 - 15:35
fonte
0

Nessuno dei due. C'è già è una notazione perfettamente buona per il prodotto punto di due vettori:

vec1⋅vec2

Perché vuoi inventarne uno nuovo?

Ecco un semplice esempio in Haskell:

a ⋅ b = foldl1 (+) $ zipWith (*) a b

infixl 7 ⋅

main = putStrLn $ show $ [1, 3, -5] ⋅ [4, -2, -1]
-- 3

Ciò dichiara di essere un operatore di inflessione di sinistra al livello di precedenza 7, che è la stessa associatività, fissità e precedenza degli altri operatori di moltiplicazione di Haskell. (Anche se, in generale, il prodotto puntino di solito non è associativo, quindi potresti voler renderlo infix 7 invece, per evitare confusione.)

Ecco un altro esempio in Scala:

sealed case class Vector[T](ns: T*)(implicit n: Numeric[T]) {
  def ⋅(o: Vector[T]) =
    ns zip o.ns map {case (a, b) => n.times(a, b) } reduceLeft (n.plus _)
}

println(Vector(1, 3, -5)⋅Vector(4, -2, -1))
// 3

Purtroppo, Scala non supporta la precedenza o l'associatività definite dall'utente.

E anche in un linguaggio molto restrittivo come Ruby, che sfortunatamente non supporta affatto gli operatori definiti dall'utente, puoi comunque ottenere un risultato abbastanza ragionevole semplicemente usando un semplice vecchio metodo invece di un operatore:

#encoding: UTF-8

class Vector
  def initialize(*ns)
    @ns = ns
  end

  def ⋅ o
    ns.zip(o.ns).map{|a, b| a*b }.reduce(:+)
  end

  protected

  attr_reader :ns
end

def Vector(*ns)
  Vector.new(*ns)
end

puts Vector(1, 3, -5).⋅ Vector(4, -2, -1)
# 3

O in Clojure:

(defn ⋅ [a b] (reduce + (map * a b)))

(println (⋅ [1 3 -5] [4 -2 -1]))

[Nota: l'esempio è ovviamente molto semplicistico, dal momento che usa una semplice lista di numeri per la rappresentazione vettoriale. Ovviamente, in un'implementazione vettoriale real , dovresti utilizzare un tipo di vettore appropriato.]

    
risposta data 13.04.2011 - 17:36
fonte

Leggi altre domande sui tag