4

我对构建导数计算器很感兴趣。我绞尽脑汁想解决这个问题,但我根本没有找到正确的解决方案。您可以提示如何开始吗?谢谢

对不起!我显然想进行符号区分。

假设你有函数 f(x) = x^3 + 2x^2 + x

我想显示导数,在这种情况下 f'(x) = 3x^2 + 4x + 1

我想在 iPhone 的objective-c 中实现它。

4

6 回答 6

7

我假设您正在尝试找到函数的精确导数。(符号分化)

您需要解析数学表达式并将各个操作存储在树结构中的函数中。

例如,x + sin²(x)将存储为+运算,应用于 and 的表达式和x^取幂)运算。sin(x)2

然后,您可以通过将微分规则应用于每个节点来递归地微分树。例如,一个+节点会变成u' + v',一个*节点会变成uv' + vu'

于 2010-05-25T14:25:36.963 回答
4

你需要记住你的微积分。基本上你需要两件事:基本函数的派生表和如何派生复合表达式的规则(如d(f + g)/dx = df/dx + dg/dx)。然后使用表达式解析器并递归地去其他树。( http://www.sosmath.com/tables/derivative/derivative.html )

于 2010-05-25T14:26:56.953 回答
4

将您的字符串解析为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 重新转换为字符串形式,再次使用递归函数

于 2010-05-25T14:33:54.430 回答
2

SLaks 已经描述了符号微分的过程。我只想补充几点:

  • 符号数学主要是解析和树转换。ANTLR 对两者都是一个很好的工具。我建议从这本很棒的书《语言实现模式》开始
  • 有一些开源程序可以满足您的需求(例如 Maxima)。剖析这样的程序也可能很有趣(但如果您首先尝试自己编写它,可能更容易理解发生了什么)
  • 可能,您还希望对输出进行某种简化。例如,仅将基本的派生规则应用于表达式2 * x就会产生2 + 0*x。这也可以通过树处理来完成(例如,通过转换0 * [...]0[...] + 0[...]等等)
于 2010-05-25T14:43:44.760 回答
1

您要计算哪种操作的导数?如果您允许使用正弦、余弦和正切等三角函数,这些可能最好存储在表格中,而多项式等其他函数可能更容易处理。您是否允许函数具有多个输入,例如 f(x,y) 而不仅仅是 f(x)?

我建议使用单个变量中的多项式,然后考虑添加三角函数、对数函数、指数函数和其他高级函数来计算可能更难做的导数。

于 2010-05-25T14:31:40.130 回答
1

忽略函数或其导数未定义的区域,对常见函数(+、-、*、/、^、sin、cos 等)进行符号区分很容易。困难的,也许是违反直觉的,是事后简化结果。

要进行微分,请将操作存储在树中(甚至仅以波兰表示法),并制作每个基本操作的导数表。然后重复应用链式法则和初等导数,同时将常数的导数设置为 0。这既快速又易于实现。

于 2010-06-01T18:26:18.263 回答