计算器 abacus 技术文档之三----自定义函数
2013-06-16 10:06
204 查看
计算器 abacus 是一个小巧却功能齐备的计算器,支持四则混合运算(包括逻辑运算),支持大量的数学函数,支持变量参与运算,支持自定义函数以扩充功能。目前版本是 2,地址:http://www.oschina.net/code/snippet_736932_13725。本文就自定义函数作一介绍。
用户可以将含有参数的表达式定义为一个新函数,以实现含参表达式的复用,对于一元二次方程求根,可以定义函数
SolveEqution1x2p(a, b, c) = (- b + sqrt(b ^ 2 - 4 * a * c)) / (2 * a)
那么没有参数的表达式就不能定义成函数吗?照样可以,只要你喜欢,假使你不喜欢使用符号常量,你仍然可以通过定义函数来使用圆周率:Pi() = 3.141593,然后在需要圆周率的地方调用它就行了。进一步,可以在已定义函数的基础上定义新的函数,比如你定义了圆的面积函数(下式中pi 是符号常量,圆周率):
AreaCircle(r) = pi * r * r
就可以继续定义圆环的面积
AreaRing(r1, r2) = AreaCircle(r1)- AreaCircle(r2)
如何,很刺激吧?我们来看一个更有趣的例子,先介绍一下程序内置的 if 条件函数
if(x, a, b)
这个函数有三个参数,当第一个参数 x 不为零时函数返回第二个参数 a,当第一个参数为零时返回第三个参数 b,从而实现选择的功能,实际上由于程序提供了关系运算符,我们完全可以自己来定义这个函数(下式中双等号 == 表示相等,单等号是用作赋值符号的)
if(x, a, b) = a + (b - a) * (x == 0)
有了这个函数,我们甚至可以写出这样的阶乘函数
factorial(n) = if(n == 0, 1, n * factorial(n - 1))
意思是
factorial(0) = 1, factorial(n) = n * factorial(n - 1)
这个例子是如此的特殊,在函数的定义体中居然出现了它自己,这叫做递归,实现起来并没有技术障碍。同样的方式,我们可以这样计算余弦
cos(x) = if(abs(x) < 0.000001, 1, 2 * cos(x / 2) ^ 2 - 1)
这个计算是近似的,当 x 充分接近 0 的时候,取 1 为它的余弦值,否则先计算它的一半的余弦,再按倍角公式计算它自己的余弦。这技术的确很诱人,但是这会导致一个问题,就是函数之间的依赖关系,这在删除函数的时候会导致问题,如果我把圆的面积函数给删除了,那前面那个圆环的面积函数还可以使用吗?有一种思路,就是在处理用户自定义函数时采用一个原则:如果在定义函数时使用了已经定义的其他函数,内部最终必须转化为只依赖于内置函数,这样,这个圆环的面积函数在经过处理后,内部事实上是
pi * r1 * r1 - pi * r2 * r2
不过这个解决方法也是有缺陷的,首先是不支持递归,比如上面的阶乘函数将变得不可能,因为会陷入无穷替换,更严重的问题是它会导致错误信息变得不可理解,比如我们不喜欢符号常量,我们自己写一个函数来计算圆周率:Pi(),而且这个函数是有可能会计算失败的,然后定义圆的面积为
AreaCircle(r) = Pi() * r * r
再定义圆环的面积为
AreaRing(r1, r2)= AreaCircle(r1) - AreaCircle(r2)
那么按照前面所述的原则,在定义完成后计算器内部实际保存的是 Pi() * r1 * r1 - Pi() * r2 * r2,然后我们调用这个圆环的面积函数,可能会得出一个对函数 Pi() 的调用失败的提示,咋一看,不对呀,我们这里并没有调用函数 Pi() 呀,于是就丈二和尚摸不着头脑了。鉴于这两个原因,程序中将不采用上面这种原则,而采用构造依赖关系表来解决这个问题,每个函数在定义时将会构造一个它所依赖的函数列表(如果有递归,则对自己的依赖不会记入此列表),在删除函数的时候,会先删除依赖它的函数,包括间接依赖它的函数,然后再删除它自己。
用户可以将含有参数的表达式定义为一个新函数,以实现含参表达式的复用,对于一元二次方程求根,可以定义函数
SolveEqution1x2p(a, b, c) = (- b + sqrt(b ^ 2 - 4 * a * c)) / (2 * a)
那么没有参数的表达式就不能定义成函数吗?照样可以,只要你喜欢,假使你不喜欢使用符号常量,你仍然可以通过定义函数来使用圆周率:Pi() = 3.141593,然后在需要圆周率的地方调用它就行了。进一步,可以在已定义函数的基础上定义新的函数,比如你定义了圆的面积函数(下式中pi 是符号常量,圆周率):
AreaCircle(r) = pi * r * r
就可以继续定义圆环的面积
AreaRing(r1, r2) = AreaCircle(r1)- AreaCircle(r2)
如何,很刺激吧?我们来看一个更有趣的例子,先介绍一下程序内置的 if 条件函数
if(x, a, b)
这个函数有三个参数,当第一个参数 x 不为零时函数返回第二个参数 a,当第一个参数为零时返回第三个参数 b,从而实现选择的功能,实际上由于程序提供了关系运算符,我们完全可以自己来定义这个函数(下式中双等号 == 表示相等,单等号是用作赋值符号的)
if(x, a, b) = a + (b - a) * (x == 0)
有了这个函数,我们甚至可以写出这样的阶乘函数
factorial(n) = if(n == 0, 1, n * factorial(n - 1))
意思是
factorial(0) = 1, factorial(n) = n * factorial(n - 1)
这个例子是如此的特殊,在函数的定义体中居然出现了它自己,这叫做递归,实现起来并没有技术障碍。同样的方式,我们可以这样计算余弦
cos(x) = if(abs(x) < 0.000001, 1, 2 * cos(x / 2) ^ 2 - 1)
这个计算是近似的,当 x 充分接近 0 的时候,取 1 为它的余弦值,否则先计算它的一半的余弦,再按倍角公式计算它自己的余弦。这技术的确很诱人,但是这会导致一个问题,就是函数之间的依赖关系,这在删除函数的时候会导致问题,如果我把圆的面积函数给删除了,那前面那个圆环的面积函数还可以使用吗?有一种思路,就是在处理用户自定义函数时采用一个原则:如果在定义函数时使用了已经定义的其他函数,内部最终必须转化为只依赖于内置函数,这样,这个圆环的面积函数在经过处理后,内部事实上是
pi * r1 * r1 - pi * r2 * r2
不过这个解决方法也是有缺陷的,首先是不支持递归,比如上面的阶乘函数将变得不可能,因为会陷入无穷替换,更严重的问题是它会导致错误信息变得不可理解,比如我们不喜欢符号常量,我们自己写一个函数来计算圆周率:Pi(),而且这个函数是有可能会计算失败的,然后定义圆的面积为
AreaCircle(r) = Pi() * r * r
再定义圆环的面积为
AreaRing(r1, r2)= AreaCircle(r1) - AreaCircle(r2)
那么按照前面所述的原则,在定义完成后计算器内部实际保存的是 Pi() * r1 * r1 - Pi() * r2 * r2,然后我们调用这个圆环的面积函数,可能会得出一个对函数 Pi() 的调用失败的提示,咋一看,不对呀,我们这里并没有调用函数 Pi() 呀,于是就丈二和尚摸不着头脑了。鉴于这两个原因,程序中将不采用上面这种原则,而采用构造依赖关系表来解决这个问题,每个函数在定义时将会构造一个它所依赖的函数列表(如果有递归,则对自己的依赖不会记入此列表),在删除函数的时候,会先删除依赖它的函数,包括间接依赖它的函数,然后再删除它自己。
相关文章推荐
- 计算器 abacus 实现技术文档之一----开篇
- 计算器 abacus 技术文档之二----初步设计
- 计算器 abacus 技术文档(一)----初步设计
- 构建一个轻量级的嵌入式虚拟平台,开发工程用板stm32 picoc解释器,大量自定义函数,sarm拓展,lwip移植,nes模拟器移植,系统优化,等等技术的融合
- 鹤鸣计算器3.26,一款安卓自定义函数公式的安卓计算器
- SQL Server技术问题之自定义函数优缺点
- 【JEECG技术文档】online自定义模板的使用
- PHP自定义函数官方文档
- Oracle技术之基于自定义函数的Function-Based索引创建
- 【JEECG技术文档】数据权限自定义SQL表达式用法说明
- 在线全部免费技术视频、在线查看API文档
- 安卓杂记(四)利用自定义的PolyBezier()函数将一系列散点绘制成光滑曲线(二)
- SQL注射技术总结文档
- html&JavaScript&innerHTML演练(计算器):获取HTML内容、函数、按钮(三)
- JavaCC技术手册之JJTree参考文档
- 【技术】C#、C++、JAVA中虚函数和抽象函数的概念对比
- 使用hive自定义函数pom.xml的写法
- MFC技术内幕系列之(五)---MFC文档序列化内幕
- javascript的trim,ltrim,rtrim自定义函数
- smarty内建函数和自定义插件函数的使用