云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

消息队列_取消代理服务器_高性价比

小七 141 0

星期五的乐趣:用gnumake生成Fibonacci数

没有人会声称gnumake是一种通用编程语言,但只要稍加努力,我们就可以强迫它为我们生成Fibonacci数。为什么这么麻烦?因为我们可以。首先,让我做一个简单的演示。这是生成文件:16:=x x x x x x x x x x x x x x x x x x输入整数:=$(foreach a,$(16),$(foreach b,$(16),$(foreach c,$(16),$(16)))解码=$(单词$1)encode=$(单词表1,$1,$(输入整数))decr=$(单词表2,$(单词$1),$1)decr2=$(单词表3,$(单词$1),$1)eq=$(过滤器$(单词$1),$(单词$2))g0号:=g1:=xfib=$(如果$(filter out undefined,$(origin f$1)),$(f$1),$(如果$(调用eq,$1,$(g0)),$(评估f$1:=$(g0))$(g0),$(如果$(调用eq,$1,$(g1)),$(评估f$1:=$(g1))$(g1),$减少$(FICALL)$(FICALL,$减少1美元)打印=$(如果$1,$(调用打印,$(call decr,$1))$(info$(call decode,$1):$(call decode,$(f$1))),信息:0美元):@:$(如果x$(调用fib,$(call encode,$@)),$(call print,$(call encode,$@)),)用一个参数调用它,序列的长度生成:ericm@chester:~/blog/fibonacci$gmake 100:01: 12: 13: 二4: 三5: 五6: 八7: 十三8: 219: 34个10: 55漂亮!现在,尽管这个演示不是特别实用,但它确实使用了一些高级的gmake概念:算术、缓存动态生成的变量以及递归函数.算术这在不支持算术运算的情况下是可能的。下面是一个如何工作的简要说明(更多细节,请参阅Make先生的文章"学习gnumake函数与算术"):我们使用空格分隔的x字符字符串来表示值;例如,数字5表示为x x x x x。为了把数字加在一起,我们连接字符串表示,而要减去,我们从字符串中删去适当数量的x。要从字符串表示转换为数值,我们只需使用$(words)内置函数计算字符串中的x数,最后,为了从数值转换为字符串表示,我们从一个只有几千个x的规范字符串中提取适当数量的x,这在内存和时间上都是低效的。50000字节的数值需要一个双字节的存储。从字符串表示转换为数值是一种线性操作,它随值的大小而变化——值越大,转换所需的时间就越长。这些因素共同限制了使用此方案实际使用的数字范围,尽管它适用于较小的值(大约10000个左右)。对于Fibonacci makefile,效率低下意味着我们只能生成约为第40个值的序列。那时,gmake已经占用了1.4gb的内存!缓存动态值因为用这种方法计算斐波纳契数很耗时,所以我们希望缓存结果,所以我们永远不会重复工作。但是这些值是动态生成的。因此,变量本身必须是动态生成的——我们事先不知道要计算哪些斐波纳契数。那么如何在gmake中动态生成变量并缓存它们的值呢?使用$(eval)。你可以在另一篇Mr.Make的文章$(eval)和宏缓存中读到这一切。在我们的Fibonacci makefile中,可以看到,当我们确定每个Fibonacci数时,我们调用$(eval)来保存值。然后设置fib函数,首先检查是否存在缓存值,如果没有缓存,则只关心计算入口.递归函数Fibonacci序列递归地定义为f(n)=f(n-1)+f(n-2),因此我们在实现中自然使用递归函数。fib函数接受一个参数,即要计算的Fibonacci数的索引,使用上述方案进行编码。在检查缓存之后,fib检查当前索引是0还是1。按照惯例,这些Fibonacci数被定义为分别为0和1,因此不需要计算它们。作为一个终止条件,我们也不能无限。如果当前索引既不是0也不是1,然后fib递归地调用自己两次,以计算前面的两个Fibonacci值。递归结果被合并、缓存并作为fib函数的整体结果返回本身。结论我很惊讶gmake计算序列的速度有多快。在我的笔记本电脑上,gmake只需几秒钟就可以计算出前30个值。在这之后,算术运算的低效就开始发挥作用了:计算35个值需要3.5秒,计算39个值需要25秒。尽管如此,考虑到环境的局限性,我认为这是令人印象深刻的,它的工作。