python實現微分函數,兩種計算方式對比,一個誤區

v1是f(x+h)-f(x)的版本,不加後綴的版本是f(x+h)-f(x-h)的,就是所謂左右兩側更精準的那個版本,但是做對比的時候,直覺上有些問題存在,如果是f(x)=x**2,是變化的斜率,左右兩側同時計算差值是可能帶來更精準的計算,但是永遠都是麼?f(x)=2*x呢?f(x+h)-f(x-h)和f(x+2h)-f(x)有什麼區別?所以就有了v1_2版本和不加後綴版本函數的對比

#https://blog.csdn.net/huqinweI987/article/details/102858397
import numpy as np

def numerical_diff_v1(x,f):
    h = 1e-4#1e-50 useless,because of underflow
    # debug_a = f(x+h)
    # debug_b = f(x)
    return (f(x+h)-f(x)) / h
def numerical_diff_v1_2(x,f):#v1 is not fair
    h = 1e-4#-50 useless
    # debug_a = f(x+h)
    # debug_b = f(x)
    # return (f(x+2*h)-f(x)) / 2*h#wrong expression,this will multiply by h
    return (f(x+2*h)-f(x)) / (2*h)
def numerical_diff(x,f):#new
    h = 1e-4
    return (f(x+h) - f(x-h)) / (2*h)


def func(x):
    y = 2*x
    return y
def func2(x):
    y = x**2
    return y
def func3(x):
    # print(0.01*x**2)
    return 0.01*x**2 + 0.1*x



x = 5
analytic_diff = 2
analytic_diff2 = 2*x
analytic_diff3 = 0.01*x + 0.1
print('func3:',func3(1))
print('func3:',func3(2))

print('func3 diff:',numerical_diff(x,func3))#1.9999999999908982e-09   0.1999999999990898
print('func3 diff:',numerical_diff_v1(x,func3))#func3 diff: 0.20000099999917254
print('func3 diff:',numerical_diff_v1_2(x,func3))




print('################################################\nfunc2:')
diff_v1 = numerical_diff_v1(x,func2)
diff = numerical_diff(x,func2)
diff_v1_v2 = numerical_diff_v1_2(x,func2)
print('diff:'.rjust(10),diff)
print('diff_v1:'.rjust(10),diff_v1)
print('diff_v1_2:'.rjust(10),diff_v1_v2)
if np.abs(diff - analytic_diff2) < np.abs(diff_v1 - analytic_diff2):
    print('the new diff are more accuracy than diff_v1!')

elif np.abs(diff - analytic_diff2) == np.abs(diff_v1 - analytic_diff2):
    print('draw')
else:
    print('ah')

if np.abs(diff - analytic_diff2) < np.abs(diff_v1_v2 - analytic_diff2):
    print('the new diff are more accuracy than diff_v1_v2!')

elif np.abs(diff - analytic_diff2) == np.abs(diff_v1_v2 - analytic_diff2):
    print('draw')
else:
    print('ah')

print('################################################\nfunc:')

diff_v1 = numerical_diff_v1(x,func)
diff = numerical_diff(x,func)
diff_v1_v2 = numerical_diff_v1_2(x,func)

print('diff:'.rjust(10),diff)
print('diff_v1:'.rjust(10),diff_v1)
print('diff_v1_2:'.rjust(10),diff_v1_v2)
if np.abs(diff - analytic_diff) < np.abs(diff_v1 - analytic_diff):
    print('the new diff are more accuracy than diff_v1!')
elif np.abs(diff - analytic_diff) == np.abs(diff_v1 - analytic_diff):
    print('draw')
else:
    print('ah')


if np.abs(diff - analytic_diff) < np.abs(diff_v1_v2 - analytic_diff):
    print('the new diff are more accuracy than diff_v1_2!')
elif np.abs(diff - analytic_diff) == np.abs(diff_v1_v2 - analytic_diff):
    print('draw!!!!!!!!!!!!!!!!!!!!')
else:
    print('ah,reverse!!!!!!!!!!!!!!!!')
# print('np.abs(diff - analytic_diff) < np.abs(diff_v1 - analytic_diff):',np.abs(diff - analytic_diff),np.abs(diff_v1 - analytic_diff),np.abs(diff - analytic_diff) < np.abs(diff_v1 - analytic_diff))



print('################################################\nfunc3:')
diff_v1 = numerical_diff_v1(x,func3)
diff = numerical_diff(x,func3)
diff_v1_v2 = numerical_diff_v1_2(x,func3)
print('diff:'.rjust(10),diff)
print('diff_v1:'.rjust(10),diff_v1)
print('diff_v1_2:'.rjust(10),diff_v1_v2)
if np.abs(diff - analytic_diff3) < np.abs(diff_v1 - analytic_diff3):
    print('the new diff are more accuracy than diff_v1!')
elif np.abs(diff - analytic_diff3) == np.abs(diff_v1 - analytic_diff3):
    print('draw')
else:
    print('ah')
# print('np.abs(diff - analytic_diff3) * 100 < np.abs(diff_v1 - analytic_diff3):',np.abs(diff - analytic_diff3) * 100 < np.abs(diff_v1 - analytic_diff3))


if np.abs(diff - analytic_diff3) < np.abs(diff_v1_v2 - analytic_diff3):
    print('the new diff are more accuracy than diff_v1_2!')
elif np.abs(diff - analytic_diff3) == np.abs(diff_v1_v2 - analytic_diff3):
    print('draw')
else:
    print('ah')











#maybe multiply by 10 is a error,makes no sense
# print(10e-50)
# print(1e-49)
# print(10e-50 == 1e-49)
# print(np.float32(10e-50))
# print(np.float64(10e-50))
# test = 10e-50
# print(type(test))

實測是沒區別的,實際結果,和diff_v1打平,和diff_v1_2比反倒不如(可能只是實現上的精度問題,暫時理解爲差不多)。

func:
     diff: 1.9999999999953388
  diff_v1: 1.9999999999953388
diff_v1_2: 2.0000000000042206
draw
ah,reverse!!!!!!!!!!!!!!!!

至於f(x)=x**2,當然,仍然是新版本更精確。

 

測這個是因爲,一些教材和人,在這個問題的說明上,至少是不嚴謹的(用2h的距離對比h的距離,至少是不公平的)。當然,這只是一個簡單的驗證,說明要多思考,實際上爲了更廣泛的適應性,肯定還是非線性的情況更多,也就是最後那個版本效果更好。

 

本文相關所有代碼

https://github.com/huqinwei/python_deep_learning_introduction/

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章