python实现微分函数,两种计算方式对比,一个误区

mac2025-07-22  8

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/

 

 

 

最新回复(0)