Vector: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Sidef)
m (→‎{{header|Sidef}}: replaced explicit angle conversions with `deg2rad` and `deg2rad`)
Line 695: Line 695:
var u = Vector(x => 3, y => 4)
var u = Vector(x => 3, y => 4)
var v = Vector(from => [1, 0], to => [2, 3])
var v = Vector(from => [1, 0], to => [2, 3])
var w = Vector(length => 1, angle => Number.pi/4)
var w = Vector(length => 1, angle => 45.deg2rad)


say u #: vec[3, 4]
say u #: vec[3, 4]
Line 702: Line 702:


say u.length #: 5
say u.length #: 5
say u.angle*180/Number.pi #: 53.13010235415597870314438744090659
say u.angle.rad2deg #: 53.13010235415597870314438744090659


say u+v #: vec[4, 7]
say u+v #: vec[4, 7]

Revision as of 19:20, 19 March 2016

Vector is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Implement a Vector class (or a set of functions) that models a Physical Vector. You should implement the four basic operations and a 'pretty print' function. Your Vector may be initialized in any reasonable way.

- Start and end points and direction - Angular coefficient and value (length)

The four operations to be implemented are:

  • Vector+Vector addition
  • Vector-Vector subtraction
  • Vector*scalar multiplication
  • Vector/scalar division

Go

<lang go>package main

import "fmt"

type vector []float64

func (v vector) add(v2 vector) vector {

   r := make([]float64, len(v))
   for i, vi := range v {
       r[i] = vi + v2[i]
   }
   return r

}

func (v vector) sub(v2 vector) vector {

   r := make([]float64, len(v))
   for i, vi := range v {
       r[i] = vi - v2[i]
   }
   return r

}

func (v vector) scalarMul(s float64) vector {

   r := make([]float64, len(v))
   for i, vi := range v {
       r[i] = vi * s
   }
   return r

}

func (v vector) scalarDiv(s float64) vector {

   r := make([]float64, len(v))
   for i, vi := range v {
       r[i] = vi / s
   }
   return r

}

func main() {

   v1 := vector{5, 7}
   v2 := vector{2, 3}
   fmt.Println(v1.add(v2))
   fmt.Println(v1.sub(v2))
   fmt.Println(v1.scalarMul(11))
   fmt.Println(v1.scalarDiv(2))

}</lang>

Output:
[7 10]
[3 4]
[55 77]
[2.5 3.5]

J

These are primitive (built in) operations in J:

<lang J> 5 7+2 3 7 10

  5 7-2 3

3 4

  5 7*11

55 77

  5 7%2

2.5 3.5</lang>

A few things here might be worth noting:

J treats a sequences of space separated numbers as a single word, this is analogous to how languages which support a "string" data type support treating strings with spaces in them as single words. Put differently: '5 7' is a sequence of three characters but 5 7 (without the quotes) is a sequence of two numbers.

J uses the percent sign to represent division. This is a visual pun with the "division sign" or "obelus" which has been used to represent the division operation for hundreds of years.

In J, a single number (or single character) is special. It's not a treated as a sequence except in contexts where you explicitly declare it to be one (for example, by prefixing it with a comma). (If it were treated as a sequence the above 5 7*11 and 5 7%2 operations would have been errors, because of the vector length mis-match.)

It's perhaps also worth noting that J allows you to specify complex numbers using polar coordinates, and complex numbers can be converted to vectors using the special token (+.) - for example:

<lang J> 2ad45 1.41421j1.41421

  +. 2ad45

1.41421 1.41421

  2ar0.785398

1.41421j1.41421

  +. 2ar0.785398

1.41421 1.41421</lang>

In the construction of these numeric constants, ad is followed by an angle in degrees while ar is followed by an angle in radians. This practice of embedding letters in a numeric constant is analogous to the use of exponential notation when describing some floating point numbers.

jq

Works with: jq version 1.4

In the following, the vector [x,y] is represented by the JSON array [x,y].

For generality, the pointwise operations (multiply, divide, negate) will work with conformal arrays of any dimension, and sum/0 accepts any number of same-dimensional vectors. <lang jq>def polar(r; angle):

 [ r*(angle|cos), r*(angle|sin) ];
  1. If your jq allows multi-arity functions, you may wish to uncomment the following line:
  2. def polar(r): [r, 0];

def polar2vector: polar(.[0]; .[1]);

def vector(x; y):

 if (x|type) == "number" and (y|type) == "number" then [x,y]
 else error("TypeError")
 end;
  1. Input: an array of same-dimensional vectors of any dimension to be added

def sum:

 def sum2: .[0] as $a | .[1] as $b | reduce range(0;$a|length) as $i ($a; .[$i] += $b[$i]);
 if length <= 1 then .
 else reduce .[1:][] as $v (.[0] ; [., $v]|sum2)
 end;

def multiply(scalar): [ .[] * scalar ];

def negate: multiply(-1);

def minus(v): [., (v|negate)] | sum;

def divide(scalar):

 if scalar == 0 then error("division of a vector by 0 is not supported")
 else [ .[] / scalar ]
 end;

def r: (.[0] | .*.) + (.[1] | .*.) | sqrt;

def atan2:

 def pi: 1 | atan * 4;
 def sign: if . < 0 then -1 elif . > 0 then 1 else 0 end;
 .[0] as $x | .[1] as $y
 | if $x == 0 then $y | sign * pi / 2
   else  ($y / $x) | if $x > 0 then atan elif . > 0 then atan - pi else atan + pi end
   end;

def angle: atan2;

def topolar: [r, angle];</lang>

Examples <lang jq>def examples:

 def pi: 1 | atan * 4;
 [1,1] as $v
 | [3,4] as $w
 | polar(1; pi/2) as $z
 | polar(-2; pi/4) as $z2
 | "v     is \($v)",
   "    w is \($w)",
   "v + w is \([$v, $w] | sum)",
   "v - w is \( $v |minus($w))",
   "  - v is \( $v|negate )",
   "w * 5 is \($w | multiply(5))",
   "w / 2 is \($w | divide(2))",
   "v|topolar is \($v|topolar)",
   "w|topolar is \($w|topolar)",
   "z = polar(1; pi/2) is \($z)", 
   "z|topolar is \($z|topolar)",
   "z2 = polar(-2; pi/4) is \($z2)",
   "z2|topolar is \($z2|topolar)",
   "z2|topolar|polar is \($z2|topolar|polar2vector)" ;

examples</lang>

Output:

<lang sh>$ jq -r -n -f vector.jq v is [1,1]

   w is [3,4]

v + w is [4,5] v - w is [-2,-3]

 - v is [-1,-1]

w * 5 is [15,20] w / 2 is [1.5,2] v|topolar is [1.4142135623730951,0.7853981633974483] w|topolar is [5,0.9272952180016122] z = polar(1; pi/2) is [6.123233995736766e-17,1] z|topolar is [1,1.5707963267948966] z2 = polar(-2; pi/4) is [-1.4142135623730951,-1.414213562373095] z2|topolar is [2,-2.356194490192345] z2|topolar|polar is [-1.414213562373095,-1.4142135623730951]</lang>

ooRexx

<lang oorexx>v=.vector~new(12,-3); Say "v=.vector~new(12,-3) =>" v~print v~ab(1,1,6,4); Say "v~ab(1,1,6,4) =>" v~print v~al(45,2); Say "v~al(45,2) =>" v~print w=v~'+'(v); Say "w=v~'+'(v) =>" w~print x=v~'-'(w); Say "x=v~'-'(w) =>" x~print y=x~'*'(3); Say "y=x~'*'(3) =>" y~print z=x~'/'(0.1); Say "z=x~'/'(0.1) =>" z~print

class vector
attribute x
attribute y
method init

Use Arg a,b self~x=a self~y=b

method ab /* set vector from point (a,b) to point (c,d) */

Use Arg a,b,c,d self~x=c-a self~y=d-b

method al /* set vector given angle a and length l */

Use Arg a,l self~x=l*rxCalccos(a) self~y=l*rxCalcsin(a)

method '+' /* add: Return sum of self and argument */

Use Arg v x=self~x+v~x y=self~y+v~y res=.vector~new(x,y) Return res

method '-' /* subtract: Return difference of self and argument */

Use Arg v x=self~x-v~x y=self~y-v~y res=.vector~new(x,y) Return res

method '*' /* multiply: Return self multiplied by t */

Use Arg t x=self~x*t y=self~y*t res=.vector~new(x,y) Return res

method '/' /* divide: Return self divided by t */

Use Arg t x=self~x/t y=self~y/t res=.vector~new(x,y) Return res

method print /* prettyprint a vector */

return '['self~x','self~y']'

requires rxMath Library</lang>
Output:
v=.vector~new(12,-3) => [12,-3]
v~ab(1,1,6,4)        => [5,3]
v~al(45,2)           => [1.41421356,1.41421356]
w=v~'+'(v)           => [2.82842712,2.82842712]
x=v~'-'(w)           => [-1.41421356,-1.41421356]
y=x~'*'(3)           => [-4.24264068,-4.24264068]
z=x~'/'(0.1)         => [-14.1421356,-14.1421356]

Perl 6

<lang perl6>class Vector {

   has Real $.x;
   has Real $.y;
   multi submethod BUILD (:$!x!, :$!y!) {
       *
   }
   multi submethod BUILD (:$length!, :$angle!) {
       $!x = $length * cos $angle;
       $!y = $length * sin $angle;
   }
   multi submethod BUILD (:from([$x1, $y1])!, :to([$x2, $y2])!) {
       $!x = $x2 - $x1;
       $!y = $y2 - $y1;
   }
   
   method length { sqrt $.x ** 2 + $.y ** 2 }
   method angle  { atan2 $.y, $.x }
   
   method add      ($v) { Vector.new(x => $.x + $v.x,  y => $.y + $v.y) }
   method subtract ($v) { Vector.new(x => $.x - $v.x,  y => $.y - $v.y) }
   method multiply ($n) { Vector.new(x => $.x * $n,    y => $.y * $n  ) }
   method divide   ($n) { Vector.new(x => $.x / $n,    y => $.y / $n  ) }
   
   method gist { "vec[$.x, $.y]" }

}

multi infix:<+> (Vector $v, Vector $w) is export { $v.add: $w } multi infix:<-> (Vector $v, Vector $w) is export { $v.subtract: $w } multi prefix:<-> (Vector $v) is export { $v.multiply: -1 } multi infix:<*> (Vector $v, $n) is export { $v.multiply: $n } multi infix:</> (Vector $v, $n) is export { $v.divide: $n }


          1. [ Usage example: ]#####

say my $u = Vector.new(x => 3, y => 4); #: vec[3, 4] say my $v = Vector.new(from => [1, 0], to => [2, 3]); #: vec[1, 3] say my $w = Vector.new(length => 1, angle => pi/4); #: vec[0.707106781186548, 0.707106781186547]

say $u.length; #: 5 say $u.angle * 180/pi; #: 53.130102354156

say $u + $v; #: vec[4, 7] say $u - $v; #: vec[2, 1] say -$u; #: vec[-3, -4] say $u * 10; #: vec[30, 40] say $u / 2; #: vec[1.5, 2]</lang>

PL/I

Translation of: REXX

<lang pli>*process source attributes xref or(!);

vectors: Proc Options(main);
Dcl (v,w,x,y,z) Dec Float(9) Complex;
real(v)=12; imag(v)=-3;   Put Edit(pp(v))(Skip,a);
real(v)=6-1; imag(v)=4-1; Put Edit(pp(v))(Skip,a);
real(v)=2*cosd(45);
imag(v)=2*sind(45);       Put Edit(pp(v))(Skip,a);
w=v+v;                    Put Edit(pp(w))(Skip,a);
x=v-w;                    Put Edit(pp(x))(Skip,a);
y=x*3;                    Put Edit(pp(y))(Skip,a);
z=x/.1;                   Put Edit(pp(z))(Skip,a);
pp: Proc(c) Returns(Char(50) Var);
Dcl c Dec Float(9) Complex;
Dcl res Char(50) Var;
Put String(res) Edit('[',real(c),',',imag(c),']')
                    (3(a,f(9,5)));
Return(res);
End;
End;</lang>
Output:
[ 12.00000, -3.00000]
[  5.00000,  3.00000]
[  1.41421,  1.41421]
[  2.82843,  2.82843]
[ -1.41421, -1.41421]
[ -4.24264, -4.24264]
[-14.14214,-14.14214]

Python

Implements a Vector Class that is initialized with origin, angular coefficient and value.

<lang python>class Vector:

   def __init__(self,m,value):
       self.m = m
       self.value = value
       self.angle = math.degrees(math.atan(self.m))
       self.x = self.value * math.sin(math.radians(self.angle))
       self.y = self.value * math.cos(math.radians(self.angle))
   def __add__(self,vector):
       """
       >>> Vector(1,10) + Vector(1,2)
       Vector:
           - Angular coefficient: 1.0
           - Angle: 45.0 degrees
           - Value: 12.0
           - X component: 8.49
           - Y component: 8.49
       """
       final_x = self.x + vector.x
       final_y = self.y + vector.y
       final_value = pytagoras(final_x,final_y)
       final_m = final_y / final_x
       return Vector(final_m,final_value)
   def __neg__(self):
       return Vector(self.m,-self.value)
   def __sub__(self,vector):
       return self + (- vector)
       
   def __mul__(self,scalar):
       """
       >>> Vector(4,5) * 2
       Vector:
           - Angular coefficient: 4
           - Angle: 75.96 degrees
           - Value: 10
           - X component: 9.7
           - Y component: 2.43
       """
       return Vector(self.m,self.value*scalar)
   def __div__(self,scalar):
       return self * (1 / scalar)
   
   def __repr__(self):
       """
       Returns a nicely formatted list of the properties of the Vector.
       >>> Vector(1,10)
       Vector:
           - Angular coefficient: 1
           - Angle: 45.0 degrees
           - Value: 10
           - X component: 7.07
           - Y component: 7.07
       
       """
       return """Vector:
   - Angular coefficient: {}
   - Angle: {} degrees
   - Value: {}
   - X component: {}
   - Y component: {}""".format(self.m.__round__(2),
              self.angle.__round__(2),
              self.value.__round__(2),
              self.x.__round__(2),
              self.y.__round__(2))</lang>


Racket

Translation of: Python

We store internally only the x, y components and calculate the norm, angle and slope on demand. We have two constructors one with (x,y) and another with (slope, norm).

We use fl* and fl/ to try to get the most sensible result for vertical vectors. <lang Racket>#lang racket

(require racket/flonum)

(define (rad->deg x) (fl* 180. (fl/ (exact->inexact x) pi)))

Custom printer
no shared internal structures

(define (vec-print v port mode)

 (write-string "Vec:\n" port)
 (write-string (format " -Slope: ~a\n" (vec-slope v)) port)
 (write-string (format " -Angle(deg): ~a\n" (rad->deg (vec-angle v))) port)
 (write-string (format " -Norm: ~a\n" (vec-norm v)) port)
 (write-string (format " -X: ~a\n" (vec-x v)) port)
 (write-string (format " -Y: ~a\n" (vec-y v)) port))

(struct vec (x y)

       #:methods gen:custom-write 
       [(define write-proc vec-print)])
Alternative constructor

(define (vec/slope-norm s n)

 (vec (* n (/ 1 (sqrt (+ 1 (sqr s)))))
      (* n (/ s (sqrt (+ 1 (sqr s)))))))
Properties

(define (vec-norm v)

 (sqrt (+ (sqr (vec-x v)) (sqr (vec-y v)))))

(define (vec-slope v)

 (fl/ (exact->inexact (vec-y v)) (exact->inexact (vec-x v))))

(define (vec-angle v)

 (atan (vec-y v) (vec-x v)))
Operations

(define (vec+ v w)

 (vec (+ (vec-x v) (vec-x w))
      (+ (vec-y v) (vec-y w))))

(define (vec- v w)

 (vec (- (vec-x v) (vec-x w))
      (- (vec-y v) (vec-y w))))

(define (vec*e v l)

 (vec (* (vec-x v) l)
      (* (vec-y v) l)))

(define (vec/e v l)

 (vec (/ (vec-x v) l)
      (/ (vec-y v) l)))</lang>

Tests <lang Racket>(vec/slope-norm 1 10)

(vec/slope-norm 0 10)

(vec 3 4)

(vec 0 10)

(vec 10 0)

(vec+ (vec/slope-norm 1 10) (vec/slope-norm 1 2))

(vec*e (vec/slope-norm 4 5) 2)</lang>

Output:
Vec:
 -Slope: 1.0
 -Angle(deg): 45.0
 -Norm: 10.0
 -X: 7.071067811865475
 -Y: 7.071067811865475

Vec:
 -Slope: 0.0
 -Angle(deg): 0.0
 -Norm: 10
 -X: 10
 -Y: 0

Vec:
 -Slope: 1.3333333333333333
 -Angle(deg): 53.13010235415597
 -Norm: 5
 -X: 3
 -Y: 4

Vec:
 -Slope: +inf.0
 -Angle(deg): 90.0
 -Norm: 10
 -X: 0
 -Y: 10

Vec:
 -Slope: 0.0
 -Angle(deg): 0.0
 -Norm: 10
 -X: 10
 -Y: 0

Vec:
 -Slope: 1.0
 -Angle(deg): 45.0
 -Norm: 11.999999999999998
 -X: 8.48528137423857
 -Y: 8.48528137423857

Vec:
 -Slope: 4.0
 -Angle(deg): 75.96375653207353
 -Norm: 10.000000000000002
 -X: 2.42535625036333
 -Y: 9.70142500145332

REXX

(Modeled after the J entry.)

Classic REXX has no trigonometric functions, so a minimal set is included here (needed to handle the   sin   and   cos   functions, along with angular conversion and normalization).

The angular part of the vector (when defining) is assumed to be in degrees for this program. <lang rexx>/*REXX program shows how to support math functions for vectors using functions*/ x = '(5, 7)' /*define the X vector: five and seven*/ y = '(2, 3)' /*define the Y vector: two and three*/ s1 = 11 /*define the s1 scalar: eleven */ s2 = 2 /*define the s2 scalar: two */ z = '(2, 45)' /*define vector of length 2, 45 degrees*/ call show 'define a vector (length,ºangle):', z , Vdef(z) call show 'addition (vector+vector):', x " + " y , Vadd(x,y) call show 'subtraction (vector-vector):', x " - " y , vsub(x,y) call show 'multiplication (Vector*scalar):', x " * " s1, Vmul(x,s1) call show 'division (vector/scalar):', x " ÷ " s2, Vdiv(x,s2) exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────one─liner subroutines─────────────────────*/ Vadd: procedure; arg a ',' b,c ',' d; call V#; return V$(a+c, b+d) Vsub: procedure; arg a ',' b,c ',' d; call V#; return V$(a-c, b-d) Vmul: procedure; arg a ',' b,c ',' d; call V#; return V$(ac-bd, bc+ad) Vdiv: procedure; arg a ',' b,c ',' d; call V#; return V$((ac+bd)/s, (bc-ad)/s) Vdef: procedure; arg a ',' b,c ',' d; call V#; return V$(a*sinD(b), a*cosD(b)) V_: arg __; return word(translate(__, , '{[(JI)]}') 0, 1) /*get # or 0*/ V$: parse arg r,c;_='['r; if c\=0 then _=_',' c; return _']' V#: a=V_(a);b=V_(b);c=V_(c);d=V_(d);ac=a*c;ad=a*d;bc=b*c;bd=b*d;s=c*c+d*d;return show: say right(arg(1),33) right(arg(2),20) ' ──► ' arg(3); return $fuzz: return min(arg(1), max(1, digits() - arg(2) ) ) cosD: return cos(d2r(arg(1))) sinD: return sin(d2r(d2d(arg(1)))) d2d: return arg(1) // 360 /*normalize degrees──►a unit circle. */ d2r: return r2r(d2d(arg(1))*pi()/180) /*convert degrees ──► radians. */ r2d: return d2d((arg(1)*180 /pi())) /*convert radians ──► degrees. */ r2r: return arg(1) // (pi()*2) /*normalize radians──►a unit circle. */ pi: pi=3.14159265358979323846264338327950288419716939937510582; return pi /*──────────────────────────────────trigonometric subroutines─────────────────*/ cos: procedure; parse arg x; x=r2r(x); a=abs(x); numeric fuzz $fuzz(9,9)

               if a=pi then return -1;  if a=pi*.5 | a=pi*2  then return 0
               return .sinCos(1, -1)

sin: procedure; parse arg x; x=r2r(x); numeric fuzz $fuzz(5,3)

               if x=pi*.5  then return 1;          if x==pi*1.5  then return -1
               if abs(x)=pi | x=0  then return 0;  return  .sinCos(x, +1)

.sinCos: parse arg z 1 _,i; q=x*x

                do k=2  by 2 until p=z; p=z; _=-_*q/(k*(k+i)); z=z+_; end /*k*/
        return z</lang>

output

 define a vector (length,ºangle):              (2, 45)  ──►  [1.41421294, 1.41421356]
        addition (vector+vector):    (5, 7)  +  (2, 3)  ──►  [7, 10]
     subtraction (vector-vector):    (5, 7)  -  (2, 3)  ──►  [3, 4]
  multiplication (Vector*scalar):        (5, 7)  *  11  ──►  [55, 77]
        division (vector/scalar):         (5, 7)  ÷  2  ──►  [2.5, 3.5]

Ruby

<lang ruby>class Vector

 def self.polar(r, angle=0)
   new(r*Math.cos(angle), r*Math.sin(angle))
 end
 
 attr_reader :x, :y
 
 def initialize(x, y)
   raise TypeError unless x.is_a?(Numeric) and y.is_a?(Numeric)
   @x, @y = x, y
 end
 
 def +(other)
   raise TypeError if self.class != other.class
   self.class.new(@x + other.x, @y + other.y)
 end
 
 def -@;       self.class.new(-@x, -@y)        end
 def -(other)  self + (-other)                 end
 
 def *(scalar)
   raise TypeError unless scalar.is_a?(Numeric)
   self.class.new(@x * scalar, @y * scalar)
 end
 
 def /(scalar)
   raise TypeError unless scalar.is_a?(Numeric) and scalar.nonzero?
   self.class.new(@x / scalar, @y / scalar)
 end
 
 def r;        @r     ||= Math.hypot(@x, @y)   end
 def angle;    @angle ||= Math.atan2(@y, @x)   end
 def polar;    [r, angle]                      end
 def rect;     [@x, @y]                        end
 def to_s;     "#{self.class}#{[@x, @y]}"      end
 alias inspect to_s

end

p v = Vector.new(1,1) #=> Vector[1, 1] p w = Vector.new(3,4) #=> Vector[3, 4] p v + w #=> Vector[4, 5] p v - w #=> Vector[-2, -3] p -v #=> Vector[-1, -1] p w * 5 #=> Vector[15, 20] p w / 2.0 #=> Vector[1.5, 2.0] p w.x #=> 3 p w.y #=> 4 p v.polar #=> [1.4142135623730951, 0.7853981633974483] p w.polar #=> [5.0, 0.9272952180016122] p z = Vector.polar(1, Math::PI/2) #=> Vector[6.123031769111886e-17, 1.0] p z.rect #=> [6.123031769111886e-17, 1.0] p z.polar #=> [1.0, 1.5707963267948966] p z = Vector.polar(-2, Math::PI/4) #=> Vector[-1.4142135623730951, -1.414213562373095] p z.polar #=> [2.0, -2.356194490192345]</lang>

Sidef

Translation of: Perl 6

<lang ruby>class Vector(:args) {

   has Number x
   has Number y
   method init {
       if ([:x, :y] ~~ args) {
           x = args{:x}
           y = args{:y}
       }
       elsif ([:length, :angle] ~~ args) {
           x = args{:length}*args{:angle}.cos
           y = args{:length}*args{:angle}.sin
       }
       elsif ([:from, :to] ~~ args) {
           x = args{:to}[0]-args{:from}[0]
           y = args{:to}[1]-args{:from}[1]
       }
       else {
           die "Invalid arguments: #{args}"
       }
   }
   method length { hypot(x, y) }
   method angle  { atan2(y, x) }
   method +(Vector v) { Vector(x => x + v.x,  y => y + v.y) }
   method -(Vector v) { Vector(x => x - v.x,  y => y - v.y) }
   method *(Number n) { Vector(x => x * n,    y => y * n)   }
   method /(Number n) { Vector(x => x / n,    y => y / n)   }
   method neg  { self * -1 }
   method to_s { "vec[#{x}, #{y}]" }

}

var u = Vector(x => 3, y => 4) var v = Vector(from => [1, 0], to => [2, 3]) var w = Vector(length => 1, angle => 45.deg2rad)

say u #: vec[3, 4] say v #: vec[1, 3] say w #: vec[0.70710678118654752440084436210485, 0.70710678118654752440084436210485]

say u.length #: 5 say u.angle.rad2deg #: 53.13010235415597870314438744090659

say u+v #: vec[4, 7] say u-v #: vec[2, 1] say -u #: vec[-3, -4] say u*10 #: vec[30, 40] say u/2 #: vec[1.5, 2]</lang>

Tcl

Good artists steal .. code .. from the great RS on Tcl'ers wiki. Seriously, this is a neat little procedure:

<lang Tcl>namespace path ::tcl::mathop proc vec {op a b} {

   if {[llength $a] == 1 && [llength $b] == 1} {
       $op $a $b
   } elseif {[llength $a]==1} {
       lmap i $b {vec $op $a $i}
   } elseif {[llength $b]==1} {
       lmap i $a {vec $op $i $b}
   } elseif {[llength $a] == [llength $b]} {
       lmap i $a j $b {vec $op $i $j}
   } else {error "length mismatch [llength $a] != [llength $b]"}

}

proc polar {r t} {

   list [expr {$r * cos($t)}] [expr {$r * sin($t)}]

}

proc check {cmd res} {

   set r [uplevel 1 $cmd]
   if {$r eq $res} {
       puts "Ok! $cmd \t = $res"
   } else {
       puts "ERROR: $cmd = $r \t expected $res"
   }

}

check {vec + {5 7} {2 3}} {7 10} check {vec - {5 7} {2 3}} {3 4} check {vec * {5 7} 11} {55 77} check {vec / {5 7} 2.0} {2.5 3.5} check {polar 2 0.785398} {1.41421 1.41421}</lang>

The tests are taken from J's example:

Output:
Ok! vec + {5 7} {2 3}    = 7 10
Ok! vec - {5 7} {2 3}    = 3 4
Ok! vec * {5 7} 11       = 55 77
Ok! vec / {5 7} 2.0      = 2.5 3.5
ERROR: polar 2 0.785398 = 1.4142137934519636 1.4142133312941887          expected 1.41421 1.41421

the polar calculation gives more than 6 digits of precision, and tests our error handling ;-).

zkl

This uses polar coordinates for everything (radians for storage, degrees for i/o), converting to (x,y) on demand. Math is done in place rather than generating a new vector. Using the builtin polar/rectangular conversions keeps the vectors normalized. <lang zkl>class Vector{

  var length,angle;  // polar coordinates, radians
  fcn init(length,angle){  // angle in degrees
     self.length,self.angle = vm.arglist.apply("toFloat");
     self.angle=self.angle.toRad();
  }
  fcn toXY{ length.toRectangular(angle) }
  // math is done in place
  fcn __opAdd(vector){
     x1,y1:=toXY(); x2,y2:=vector.toXY();
     length,angle=(x1+x2).toPolar(y1+y2);
     self
  }
  fcn __opSub(vector){
     x1,y1:=toXY(); x2,y2:=vector.toXY();
     length,angle=(x1-x2).toPolar(y1-y2);
     self
  }
  fcn __opMul(len){ length*=len; self }
  fcn __opDiv(len){ length/=len; self }
  fcn print(msg=""){
  1. <<<

"Vector%s:

  Length: %f
  Angle:  %f\Ub0;
  X: %f
  Y: %f"
  1. <<<
     .fmt(msg,length,angle.toDeg(),length.toRectangular(angle).xplode())
     .println();
  }
  fcn toString{ "Vector(%f,%f\Ub0;)".fmt(length,angle.toDeg()) }

}</lang> <lang zkl>Vector(2,45).println(); Vector(2,45).print(" create"); (Vector(2,45) * 2).print(" *"); (Vector(4,90) / 2).print(" /"); (Vector(2,45) + Vector(2,45)).print(" +"); (Vector(4,45) - Vector(2,45)).print(" -");</lang>

Output:
Vector(2.000000,45.000000°)
Vector create:
   Length: 2.000000
   Angle:  45.000000°
   X: 1.414214
   Y: 1.414214
Vector *:
   Length: 4.000000
   Angle:  45.000000°
   X: 2.828427
   Y: 2.828427
Vector /:
   Length: 2.000000
   Angle:  90.000000°
   X: 0.000000
   Y: 2.000000
Vector +:
   Length: 4.000000
   Angle:  45.000000°
   X: 2.828427
   Y: 2.828427
Vector -:
   Length: 2.000000
   Angle:  45.000000°
   X: 1.414214
   Y: 1.414214