从公式求值到函数单变量求导

2020-03-14 22:24:47 +08:00
 crella
业余写编程,纯属兴趣驱动。写了个小脚本,在给定 x=1 时,求出 f(x)=1+(1+(x*sin(x^2-x^3)))*6 的值。主要就是先逐步找到括号里的表达式,求值,消去括号和表达式;不断循环。

一直有个心愿把求导功能做出来。随便想了一个多月里的零碎时间,做了不少让步,包括仅限对 x 求导;暂时不用合并同类项;求导函数仅以 x 为变量;……

一开始打算扩展 Ruby 的 Float 类型,加自定义属性,把 x 设为这个自定义 Float 类的实例,像给表达式求值一样,跟踪 x 被处理的流程。后来发现难如天书,无法下手。

现在是把括号内表达式设成类 PolyList 的实例,这个类有 @store 存储表达式的切割字符列表,有 @func 记录括号外是否挂载函数(比如'sin'或者 undef ),有 @derv_list 记录当前表达式及其挂载函数的导数,也是与 @store 相似的列表。

目前版本求值也是用了 PolyList 来存储括号内表达式,求值方面通过之前写好的测试。

下午写了一些代码,发现真是太难了,什么东西放什么位置,比一开始规划的乱得多;定义每个函数的功能往往也不准确,怎么切分功能?;还不知道会不会写出互相依赖的死循环……感觉自己没有系统学习过规划项目的能力。

如果是科班学习的各位来想,怎样在已有的公式求值引擎的基础上写求导功能?

而且目前看来,合并同类项也是一个很棘手的功能。比如 a=2*x^3+x^3=3*x^3,这个初中生都会的化简,编程来写还不一定容易写。

问题:
1、用字符还是自定义类来存储 3 和 x 之类的元素?

2、如果把 x^3 存储成一个元素,那么 a=2*(x-1+1)^3+(2*x)^3/8 的合并同类项又该怎样写处理流程呢?

感觉自己还是倾向于自力更生,一旦找到已有的解决方案,就泄气了、再也不想想这个事。谁不知道有 SymPy 啊,哈哈。
769 次点击
所在节点    问与答
1 条回复
crella
2020-03-15 17:33:41 +08:00
有点开心,出了初步的成果,说明我的设想是基本可行的……

打印结果:

公式:x^2+x
求导结果: ( x * 2 ) + 1
---
公式:x*x/2
求导结果: ( ( x * 2 ) / 2.0 )
---
公式:x*sin(x)
求导结果: ( x * ( {cos{{x}}} ) + sin{x} )
---
公式:1+sin(x)/x
求导结果: 0 + ( {{cos{{x}}}, *, x, -, sin{x}} / x ^ 2 )
---
公式:sin(x^3+x^2)
求导结果: ( {cos{{x, ^, 3, +, x, ^, 2}}} * ( ( x ^ 2.0 * 3.0 ) + ( x * 2 ) ) )
---
公式:1+sin(x^3+x^2)*cos(x)
求导结果: 0 + ( sin{x, ^, 3, +, x, ^, 2} * ( {-1, *, sin{{x}}} ) + cos{x} * ( {cos{{x, ^, 3, +, x, ^, 2}}} * ( ( x ^ 2.0 * 3.0 ) + ( x * 2 ) ) ) )
---
公式:1+(1+x*sin(x^2-x^3))*6
求导结果: 0 + ( ( 0 + ( x * ( {cos{{x, ^, 2, -, x, ^, 3}}} * ( ( x * 2 ) - ( x ^ 2.0 * 3.0 ) ) ) + sin{x, ^, 2, -, x, ^, 3} ) ) * 6.0 )
---

以后如果测试更多的用例也可以的话,那么接下来最大的问题就是合并同类项了,哈哈。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/652858

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX