编程科学/常数问题
到目前为止,我们的多项式只包含一个单项式,例如
这很限制。例如,一条直线的方程
可以看作是一个多项式,其项具有一个幂,加上一个常数项,b。换句话说
我们如何处理常数项?我们可以修改我们的term构造函数,使其接受第三个参数,一个常数项。在这种情况下,我们将直线模型化为
为
term(3,1,-5)
虽然这会奏效,但当我们开始对由多个项组成的多项式建模时,这种方法会使事情变得复杂。考虑
这个多项式可以用以下项表示
term(4,4,0) term(-2,3,0) term(5,2,0) term(1,1,-3)
其中前三个项的常数项为零。或者,我们可以用这种方式表示多项式
term(4,4,1) term(-2,3,2) term(5,2,3) term(1,1,-9)
现在每个项都有一个常数项(注意所有常数项加起来为 -3,如预期的那样)。现在你应该看到给term添加第三个参数的两个问题。第一个问题是大多数项没有(或不应该有)常数项。第二个问题是不清楚在一个项集合中,哪个项应该包含常数项。
在我告诉你更好的方法之前,先给你讲个故事。我有一个朋友,他的兄弟(或表兄弟或其他,我不记得了),因为没有撬棍,就用一把克莱斯勒螺丝刀把一个相当重,而且卡得很紧的机械零件从它的外壳中撬出来。这个零件纹丝不动,于是他的兄弟(或表兄弟或其他)把全身的重量都压在了螺丝刀上,螺丝刀立刻弯了。你现在可能不知道,弯了的螺丝刀几乎不能做螺丝刀通常做的事情(比如拧紧或松开螺丝)。恰好克莱斯勒手工具有终身保修,所以他的兄弟(或表兄弟或其他)带着弯了的螺丝刀回到了西尔斯,要求更换。店员很高兴地拿了一把新的螺丝刀,并一边换螺丝刀,一边说:“你知道,西尔斯也卖克莱斯勒撬棍。”
这个故事的寓意是什么?当然,它就是用合适的工具做合适的事情。 [1]我们需要一个新的工具来表示常数项。
你可能在问,常数项到底有什么大不了的?为什么我们不能直接用数字?我们可以,但考虑一下这段对话
sway> var s = t . diff(); OBJECT: <OBJECT 4369>
假设t绑定到一个term对象。那么一切都很顺利;s也绑定到一个term对象。但假设t绑定到数字八。我们从终端得到一个更糟糕的响应
sway> var s = t . diff(); EVALUATION ERROR: :accessError dot operator used on type INTEGER
我们试图将数字八当作一个对象来处理,而它不是一个对象。由于数字是有效的数学实体,并且对数字求微分是有意义的,我们剩下两个选择
- 每次我们想求微分或找一个值或可视化时,都需要测试我们正在处理的实体是否是一个对象。
- 确保数字是具有diff、value和toString方法的对象。
第一个选择意味着我们将来编写的每一行代码都必须考虑到我们有两种类型的实体,我们最好不要忘记这一点。
第二个选择意味着在开始时花一点时间,但以后就再也不用担心多种类型的实体了。
很明显,第二个选择是我们要走的路。在我们编写表示常数的构造函数之前,我们需要问问自己三个问题
- 在特定点,常数项的值是多少?
- 常数项的导数是多少?
- 常数项的合理字符串表示是什么?
这三个问题对应于所有构造函数必须具有的三种方法。
其中第一个问题似乎有点奇怪。term的值函数计算了给定x的值时,term的值。当x变化时,term的值也会变化。但对于常数项,似乎不存在x。这不是完全正确的,因为存在一个方程,其中y的值保持不变,无论x的值是多少。一个例子是方程
我们可以绘制该方程
File:Ch05-figure01.png
我们看到,无论x的值是多少,y的值都保持不变。因此,常数对象的value方法应该忽略给定的x的值,并返回其常数值
function constant(n) { function value(x) { n; } this; }
注意,value方法始终返回n
sway> var c = constant(5);
sway> c . value(0); INTEGER: 5
sway> c . value(3); INTEGER: 5
接下来,常数项的微分是多少?换句话说,当x的值发生变化时,我们的对象的值如何变化。我们从上面的交互中看到,值根本没有变化。换句话说,变化为零。因此,你可能会倾向于将常数对象的diff方法写成
function diff() { 0; //incorrect }
然而,这将是不正确的,因为所有diff方法都必须返回本身具有diff方法的对象。我们在terms中看到了这一点:term对象的diff方法返回一个term对象,该对象具有一个diff方法,如预期的那样。对于手头的任务,应该用什么对象来表示数字零?一个常数对象!
function constant(n) { function value(x) { n; } function diff() { constant(0); } this; }
我们最后一个要回答的问题是如何可视化一个常数项?这很容易回答:我们只需将数字转换为字符串。我们得到了完整的常数构造函数
function constant(n) { function value(x) { n; } function diff() { constant(0); } function toString() { "" + n; } this; }
真是一个大的偏差!记住,我们试图用term和常数项来模拟一条直线。直线
可以用两个对象表示
term(m,1) constant(b)
当我们将它们加在一起时会发生什么?
sway> var m = 3; sway> var b = -5; sway> term(m,1) + constant(b); EVALUATION ERROR: :argumentTypeError addition: cannot add type OBJECT to type OBJECT
现在我们需要一种方法将这两个对象粘合在一起。清楚地让我们测试一下。回想一下我们的term构造函数
function term(a,n) { function value(x) { a * (x ^ n); } this; }
让我们创建一个值为 7 的常数项,看看term的最终值是否确实与x的值无关。
var c = term(7,0); sway> c . value(10); INTEGER: 7 sway> c . value(1000); INTEGER: 7
确认。
所有公式都使用小学优先级编写。
1. 使用 Sway 来表示以下多项式的各个项 . 当 时,这个多项式的值是多少?
2. 使用 Sway 来表示以下多项式的各个项 . 当 时,这个多项式的值是多少?
3. 婴儿死亡率与收入水平成反比。婴儿死亡率相对于收入水平的增长率是多少?
- ↑ 有时,计算机科学家会忽略这条规则,他们更喜欢另一个故事的寓意:下次用一把更大的螺丝刀。这是因为计算机科学家(又一次懒惰)不想从头开始写东西(一个撬棍),而是更愿意使用其他已经写好并且可以适应手头工作的工具(螺丝刀)。有时,这很好用,但有时会导致将来出现额外的复杂情况。在这种情况下,一个常数c可以用系数为c,指数为零的term来表示。相反,我们将设计我们微积分系统中的第二种对象。