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/