我对构建导数计算器很感兴趣。我绞尽脑汁想解决这个问题,但我根本没有找到正确的解决方案。您可以提示如何开始吗?谢谢
对不起!我显然想进行符号区分。
假设你有函数 f(x) = x^3 + 2x^2 + x
我想显示导数,在这种情况下 f'(x) = 3x^2 + 4x + 1
我想在 iPhone 的objective-c 中实现它。
我对构建导数计算器很感兴趣。我绞尽脑汁想解决这个问题,但我根本没有找到正确的解决方案。您可以提示如何开始吗?谢谢
对不起!我显然想进行符号区分。
假设你有函数 f(x) = x^3 + 2x^2 + x
我想显示导数,在这种情况下 f'(x) = 3x^2 + 4x + 1
我想在 iPhone 的objective-c 中实现它。
我假设您正在尝试找到函数的精确导数。(符号分化)
您需要解析数学表达式并将各个操作存储在树结构中的函数中。
例如,x + sin²(x)
将存储为+
运算,应用于 and 的表达式和x
(^
取幂)运算。sin(x)
2
然后,您可以通过将微分规则应用于每个节点来递归地微分树。例如,一个+
节点会变成u' + v'
,一个*
节点会变成uv' + vu'
。
你需要记住你的微积分。基本上你需要两件事:基本函数的派生表和如何派生复合表达式的规则(如d(f + g)/dx = df/dx + dg/dx
)。然后使用表达式解析器并递归地去其他树。( http://www.sosmath.com/tables/derivative/derivative.html )
将您的字符串解析为S 表达式(尽管这通常在 Lisp 上下文中进行,但您可以用几乎任何语言做等价的事情),最简单的是使用 lex/yacc 或等价物,然后编写一个递归的“派生”函数。在 OCaml-ish 方言中,是这样的:
let rec derive var = function
| Const(_) -> Const(0)
| Var(x) -> if x = var then Const(1) else Deriv(Var(x), Var(var))
| Add(x, y) -> Add(derive var x, derive var y)
| Mul(a, b) -> Add(Mul(a, derive var b), Mul(derive var a, b))
...
(如果您不知道 OCaml 语法 -derive
是双参数递归函数,第一个参数是变量名,第二个参数在连续行中进行数学运算;例如,如果此参数是 formAdd(x, y)
的结构,则返回Add
从两个字段,其值分别为 derivedx
和 derived y
;对于derive
可能作为参数接收的其他情况也是如此;_
在第一个模式中表示“匹配任何内容”)
在此之后,您可能有一些清理功能来整理结果表达式(减少分数等),但这会变得复杂,并且对于推导本身来说不是必需的(即,没有它您得到的仍然是正确答案)。
完成 s-exp 的转换后,将生成的 s-exp 重新转换为字符串形式,再次使用递归函数
SLaks 已经描述了符号微分的过程。我只想补充几点:
2 * x
就会产生2 + 0*x
。这也可以通过树处理来完成(例如,通过转换0 * [...]
到0
和[...] + 0
到[...]
等等)您要计算哪种操作的导数?如果您允许使用正弦、余弦和正切等三角函数,这些可能最好存储在表格中,而多项式等其他函数可能更容易处理。您是否允许函数具有多个输入,例如 f(x,y) 而不仅仅是 f(x)?
我建议使用单个变量中的多项式,然后考虑添加三角函数、对数函数、指数函数和其他高级函数来计算可能更难做的导数。
忽略函数或其导数未定义的区域,对常见函数(+、-、*、/、^、sin、cos 等)进行符号区分很容易。困难的,也许是违反直觉的,是事后简化结果。
要进行微分,请将操作存储在树中(甚至仅以波兰表示法),并制作每个基本操作的导数表。然后重复应用链式法则和初等导数,同时将常数的导数设置为 0。这既快速又易于实现。