python——向量的表示及相关计算

由于python自带的包没有向量这个概念,我们需要自己定义一个向量的类,然后利用这个类进行向量的相关计算。

下面附上相关的程序:

from math import acos,pi
from math import sqrt
from decimal import Decimal,getcontext
import numpy as np

getcontext().prec = 30

class Vector(object):
    CANNOT_NORMALIZE_ZERO_VECTOR_MSG = 'Cannot normalize the zero vector'

    def __init__(self, coordinates):
        try:
            if not coordinates:
                raise ValueError
            self.coordinates = tuple([Decimal(x) for x in coordinates])
            self.dimension = len(coordinates)
        except ValueError:
            raise ValueError('The coordinates must be nonempty')
        except TypeError:
            raise TypeError('The coordinates must be an iterable')

    def __str__(self):
            return 'Vector: {}'.format(self.coordinates)

    # 两个向量是否相等
    def __eq__(self, v):
        return self.coordinates == v.coordinates

    def __repr__(self):
        return 'Vector(%r, %r)' % (self.x, self.y)

    # 加法
    def plus(self, v):
        return Vector([x + y for x, y in zip(self.coordinates, v.coordinates)])

    # 减法
    def minus(self, v):
        return Vector([x - y for x, y in zip(self.coordinates, v.coordinates)])

    # 向量的倍数
    def times_scalar(self, m):
        return Vector([Decimal(m) * x for x in self.coordinates])

    # 向量的大小
    def magnitude(self):
        coordinates_squared = [x ** 2 for x in self.coordinates]
        return sqrt(sum(coordinates_squared))

    # 单位向量
    def normalized(self):
        try:
            magnitude = self.magnitude()
            return self.times_scalar(1.0 / magnitude)

        except ZeroDivisionError:
            raise Exception(self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG)

    # 两个向量的点积
    def dot(self, v):
        return sum([x * y for x, y in zip(self.coordinates, v.coordinates)])

    # 计算三维向量的向量积
    def cross(self, v):
        try:
            x_1, y_1, z_1 = self.coordinates
            x_2, y_2, z_2 = v.coordinates
            new_coordinates = [y_1 * z_2 - y_2 * z_1,
                               -(x_1 * z_2 - x_2 * z_1),
                               x_1 * y_2 - x_2 * y_1]
            return Vector(new_coordinates)
        except ValueError as e:
            msg = str(e)
            if msg == 'need more than 2 values to unpack':
                self_embedded_in_R3 = Vector(self.coordinates + ('0',))
                v_embedded_in_R3 = Vector(v.coordinates + ('0',))
                return self_embedded_in_R3.cross(v_embedded_in_R3)
            elif (msg == 'too many values to unpack' or
                  msg == 'need more than 1 value to unpack'):
                raise Exception('wrong value number')
        else:
            raise e

    # 两个向量之间的角度
    def angle_with(self, v, in_degrees=True):
        try:
            u1 = self.normalized()
            u2 = v.normalized()
            dots = u1.dot(u2)
            if abs(abs(dots) - 1) < 1e-10:
                if dots < 0:
                    dots = -1
                else:
                    dots = 1
            angle_in_radians = acos(dots)

            if in_degrees:
                degrees_per_radian = 180. / pi
                return angle_in_radians * degrees_per_radian
            else:
                return angle_in_radians

        except Exception as e:
            if str(e) == self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG:
                raise Exception('Cannot compute an angle with the zero vector')
            else:
                raise e

    # 判断两个向量是否正交
    def is_orthogonal_to(self, v, tolerance=1e-10):
        return abs(self.dot(v)) < tolerance

    # 是否是零向量
    def is_zero(self, tolerance=1e-10):
        return self.magnitude() < tolerance

    # 两个向量是否平行
    def is_parallel_to(self, v):
        return (self.is_zero() or
                v.is_zero() or
                self.angle_with(v) == 0 or
                self.angle_with(v) == pi)

    # 向量在另一个向量上的投影
    def component_parallel_to(self, basis):
        try:
            u = basis.normalized()
            weight = self.dot(u)
            return u.times_scalar(weight)
        except Exception as e:
            if str(e) == self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG:
                raise Exception('Cannot compute an angle with the zero vector')
            else:
                raise e

    # 向量相对于投影向量的垂直向量
    def component_orthogonal_to(self, basis):
        try:
            projection = self.component_parallel_to(basis)
            return self.minus(projection)
        except Exception as e:
            if str(e) == self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG:
                raise Exception('Cannot compute an angle with the zero vector')
            else:
                raise e

    # 两个向量组成的平行四边形 面积
    def area_of_parallelogram_with(self, v):
        cross_product = self.cross(v)
        return cross_product.magnitude()

    # 两个向量组成的三角形 面积
    def area_of_triangle_with(self, v):
        cross_product = self.cross(v)
        
# example
if __name__ == '__main__':
    v = Vector(['1', '1', '0'])
    w = Vector(['-1', '0', '0'])
    print(v.angle_with(w))

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值