Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python-计算Arcin时不准确_Python_Python 3.x_Math_Trigonometry - Fatal编程技术网

Python-计算Arcin时不准确

Python-计算Arcin时不准确,python,python-3.x,math,trigonometry,Python,Python 3.x,Math,Trigonometry,我试图在Python中实现arcsin,而不使用任何外部库 这是我的密码: from time import process_time as pt class TrigoCalc(metaclass=__readonly): # This class evaluates various Trigonometric functions # including Inverse Trigonometric functions def __setattr__(self, na

我试图在Python中实现arcsin,而不使用任何外部库

这是我的密码:

from time import process_time as pt

class TrigoCalc(metaclass=__readonly):
    # This class evaluates various Trigonometric functions 
    # including Inverse Trigonometric functions
    def __setattr__(self, name, value):
        raise Exception("Value can't be changed")
    

    @staticmethod
    def asin(x):
        '''Implementation from Taylor series
        asin(x) => summation[(2k)! * x^(2k + 1) / (2^(2k) * (k!)^2 * (2k + 1))]
                  k = [0, inf)
        x should be real
        '''
        # a0 = 1                                                                           
        # a1 = 1/(2*3)                                                                     
        # a2 = 1/2 * 3/(4*5) 
        # a3 = 1/2 * 3/4 * 5/(6*7)
        # a4 = 1/2 * 3/4 * 5/6 * 7/(8*9)
        # a5 = 1/2 * 3/4 * 5/6 * 7/8 * 9/(10*11)
        # a6 = 1/2 * 3/4 * 5/6 * 7/8 * 9/10 * 11/(12*13)
        # a7 = 1/2 * 3/4 * 5/6 * 7/8 * 9/10 * 11/12 * 13/(14*15)
        # a8 = 1/2 * 3/4 * 5/6 * 7/8 * 9/10 * 11/12 * 13/14 * 15/(16*17)
        # a9 = 1/2 * 3/4 * 5/6 * 7/8 * 9/10 * 11/12 * 13/14 * 15/16 * 17/(18*19)
        # a10 = 1/2 * 3/4 * 5/6 * 7/8 * 9/10 * 11/12 * 13/14 * 15/16 * 17/18 * 19/(20*21)
        
        # taking 10 coefficients for arriving at a common sequence
        
        # N = n, D = n + 1; (N/D) --> Multiplication, number of times the coefficient number, n >= 1
        
        start_time = pt()

        coeff_list = []
        NUM_ITER = 10000
        for k in range(NUM_ITER):
            if k == 0:
                coeff_list.append(1)
            else:
                N = 1
                D = N + 1
                C = N/D
                if k >= 2:
                    for i in range(k-1):
                        N += 2; D += 2
                        C = C * N/D
                coeff_list.append(C)
        
        __sum = 0
        for k in range(NUM_ITER):
            n = coeff_list[k] * math_utils.power(x, 2*k + 1) / (2*k + 1)
            __sum += n
    
        # Radian conversion to degrees
        __sum = __sum/TrigoCalc.pi * 180
        
        end_time = pt()

        print(f'Execution time: {end_time - start_time} seconds')

        return __sum
结果 当
NUM_ITER
60
(无限级数迭代60次)时,
x=1
极点的计算存在显著的不精确性,而
x=1/2
给出14点精度

In [2]: TrigoCalc.asin(0.5)
Execution time: 0.0 seconds
Out[2]: 30.000000000000007

In [3]: TrigoCalc.asin(1)
Execution time: 0.0 seconds
Out[3]: 85.823908877692
两次运行中的执行时间都不明显

NUM_ITER
10000
时,则在
x=1
极,结果比上一次运行更精确,但在
x=1/2
时,精度完全相同

In [4]: TrigoCalc.asin(0.5)
Execution time: 19.109375 seconds
Out[4]: 30.000000000000007

In [5]: TrigoCalc.asin(1)
Execution time: 19.109375 seconds
Out[5]: 89.67674183336727 
对于这种类型的计算,这两次运行的执行时间非常长

问题 如何平衡代码,以便在较小的
NUM_ITER
中,在
x=1
极点处至少提供1点精度

请随时提供建议或更新的代码

Python版本:3.7.7

编辑:在@Joni的答案的帮助下更改代码以获得精确的结果

  • 将无穷级数计算封装到
    asin()中的另一个函数中

  • 使用
    asin()中的新函数将限制添加到
    x
    ,以避免收敛缓慢:

     if -1.0 <= x < -0.5:
         return -(TrigoCalc.pi/2 - __arcsin_calc(math_utils.power((1 - x*x), 0.5))) / TrigoCalc.pi * 180    # Radian to Degree conversion
    
     elif -0.5 <= x <= 0.5:
         return __arcsin_calc(x)/TrigoCalc.pi * 180
    
     elif 0.5 < x <= 1.0:          
         return (TrigoCalc.pi/2 - __arcsin_calc(math_utils.power((1 - x*x), 0.5))) / TrigoCalc.pi * 180
    
     else:      
         raise ValueError("x should be in range of [-1, 1]")
    

  • 非常基本的近似值将给出
    从0到N的和
    近似
    弧心
    1e(-N)
    (以弧度表示)。 这里,您给出的是以度为单位的结果,因为度和弧度之间大致存在
    1e2
    ,因此需要设置
    NUM\u ITER=1e(N+2)
    来近似
    1e(-N)

    因此,对于您的特定问题,您需要使用
    N=1
    (约1分)进行测试,因此
    NUM_ITER=1e(1+2)=1000
    。这一点都不精确,但给出了您所寻找的价值的概念

    那么,如果你想寻找精确的值,我没有看到每次都使用精确的数学方法(无论x点的精度如何)。 但是,如果是算法的目标,则可以使用二分法算法来查找
    NUM\u ITER
    。第一个近似值将减少计算时间

    精确的近似值来自比率or
    x^O(n)
    4^O(n)
    4^O(n)
    更大。我们可以用
    O(1/10^n)
    来近似求和项


    如果有人能做一个精确的微积分,我会非常高兴看到它。

    一个非常基本的近似值将给出
    从0到N的和
    近似值
    1e(-N)
    (以弧度表示)。 这里,您给出的是以度为单位的结果,因为度和弧度之间大致存在
    1e2
    ,因此需要设置
    NUM\u ITER=1e(N+2)
    来近似
    1e(-N)

    因此,对于您的特定问题,您需要使用
    N=1
    (约1分)进行测试,因此
    NUM_ITER=1e(1+2)=1000
    。这一点都不精确,但给出了您所寻找的价值的概念

    那么,如果你想寻找精确的值,我没有看到每次都使用精确的数学方法(无论x点的精度如何)。 但是,如果是算法的目标,则可以使用二分法算法来查找
    NUM\u ITER
    。第一个近似值将减少计算时间

    精确的近似值来自比率or
    x^O(n)
    4^O(n)
    4^O(n)
    更大。我们可以用
    O(1/10^n)
    来近似求和项


    如果有人能做精确的微积分,我会非常高兴看到。

    Arcin(1)
    的问题是,
    Arcin(x)
    在x=1时垂直(导数无边界增长)。像泰勒级数这样的多项式近似法跟不上它。收敛速度很慢,需要大量的项才能得到合适的近似值。你需要改变处理问题的方式

    例如,对于小x,
    y=sin(pi/2-x)
    大约是
    1-x^2/2
    ,从中可以导出近似值
    asin(y)=pi/2-sqrt(2-2*y)
    。此近似值适用于非常接近1的值-您可以直接使用它

    如果你再努力一点,你就能证明确切的身份

    使用此标识,您可以使用对0附近的x有利的现有
    asin
    函数,为1附近的x计算
    asin(x)

    例如:要计算asin(0.99)
    ,您需要计算:

    asin(0.99) = pi/2 - 2*asin( sqrt( (1-.99)/2 ) )
               = pi/2 - 2*asin( sqrt(.005) )
               = pi/2 - 2*asin(0.07071067811865475)
    
    。。。然后,您将使用现有算法获得
    asin(0.07071067811865475)
    的高质量近似值


    这是生产质量数学库实现中使用的技术-例如,请参见或。

    Arcin(1)
    的问题是,
    Arcin(x)
    在x=1时垂直(导数无边界增长)。像泰勒级数这样的多项式近似法跟不上它。收敛速度很慢,需要大量的项才能得到合适的近似值。你需要改变处理问题的方式

    例如,对于小x,
    y=sin(pi/2-x)
    大约是
    1-x^2/2
    ,从中可以导出近似值
    asin(y)=pi/2-sqrt(2-2*y)
    。此近似值适用于非常接近1的值-您可以直接使用它

    如果你再努力一点,你就能证明确切的身份

    使用此标识,您可以使用对0附近的x有利的现有
    asin
    函数,为1附近的x计算
    asin(x)

    例如:要计算asin(0.99)
    ,您需要计算:

    asin(0.99) = pi/2 - 2*asin( sqrt( (1-.99)/2 ) )
               = pi/2 - 2*asin( sqrt(.005) )
               = pi/2 - 2*asin(0.07071067811865475)
    
    。。。然后,您将使用现有算法获得
    asin(0.07071067811865475)
    的高质量近似值

    这是第
    asin(x) = pi/2 - 2*asin( sqrt( (1-x)/2 ) )
    
    asin(0.99) = pi/2 - 2*asin( sqrt( (1-.99)/2 ) )
               = pi/2 - 2*asin( sqrt(.005) )
               = pi/2 - 2*asin(0.07071067811865475)