数与图(8)——计算的代价
在《数与图(7)》中,我们通过求多项式的值,检查出程序的bug,于是从最靠近结果的部分开始,追溯错误产生的原因,找到并最终改正了错误。本篇文章继续讨论求值的问题,我们要来评价一下计算的代价,即,计算消耗的时间。
在App Inventor中,有一个计时器组件,喜欢做游戏的读者一定知道如何用它来控制游戏时长,但它还有另一种功能,就是提供与时间有关的数据,例如“系统时间”。在项目的设计视图中添加一个计时器组件,在编程视图中取出计时器组件的“求系统时间”块,对准该块点击鼠标右键,会弹出快捷菜单,在确保已经连接了AI伴侣的前提下,选中菜单中的最后一项——执行该代码块,就可以单独运行这个代码块,程序运行结果将以注释的方式显示出来,如图1所示。
图1 用计时器组件获得与当前时间对应的毫秒数
图1中注释框内显示的一串数字,就是当前时间所对应的毫秒数,这个毫秒数指的是从1970年1月1日0时起至今的总毫秒数。通常,如果想求两个时刻之间的间隔时,只要求两个时刻的毫秒数之差即可。
在《数与图(7)》中,用到了两种多项式的求值方法——求和与求积,本篇文章就利用这两种方法,来观察计算的代价,
我们来写一段简单的程序,分别用两种方法计算当x=5时多项式的值,代码如图2所示。
图2 不同运算方法的耗时不同
图2中的这两段代码几乎完全相同,上面的代码调用了“求积”过程,而下面的代码调用了“求和”过程。测试结果显示,求和过程消耗了更多的时间。如果增加测试次数,你会发现耗时数会有所变化,有时求积的耗时还会大于求和的耗时。为了进一步探究,我们借助于循环语句,加大运算次数,代码如图3所示。
图3 五次运算的耗时对比
在图3右侧的注释框中,与左侧结果的“0”对应的是-1.4211*10-14,它反映出求和计算所产生的误差——一个接近于0的负小数。从测试结果可以看出,求和的运算耗时要大于求积的耗时。这印证了图2中的结果。
为了进一步印证这一结论,需要继续加大运算次数:在循环语句中,将循环变量的步长由原来的1减小到0.1,这样循环次数就由5次增加到50次,测试的结果如图4所示。
图4 将运算次数提高到50次时的测试结果
图4中显示的结果再次印证了前面的结论:对于同一个多项式,采用求积的方式求值,其消耗的时间要小于求和的方式。
为什么会有这样的差异呢?这是因为在求和运算中采用了乘方运算,一个6次方的运算等于5次乘法运算,仅就图2中的算式来说,求和运算中乘法运算的次数是5+5+4+3+2+1=20次,而求积运算中乘法运算的次数是5次,两者的加法运算次数相同。当运算次数较少时,两者之间的耗时差别并不大,但是,当运算次数增大时,这种差别会越来越显著。
通过本篇文章的讨论,我们了解到,对于同一个多项式,不同的计算方法(算式)对应于不同的计算量,也意味着不同的计算代价。当我们要处理的数据量足够大时,节省代价是必要的。在下一篇文章中,我们将采用求积的方式计算一组多项式的值,并利用这些值绘制相应的曲线。