我正在看一些Don Knuth教授的代码,用CWEB编写,转换为C.具体的例子是dlx1.w,可从Knuth的网站获得
在一个阶段,struct nd [cc]的.len值递减,并且以一种笨重的方式完成:
o,t=nd[cc].len-1;
o,nd[cc].len=t;
Run Code Online (Sandbox Code Playgroud)
(这是一个特定于Knuth的问题,所以也许你已经知道"o"是一个预处理器宏,用于递增"mems",这是通过访问64位字来衡量的累计工作量.) "t"中剩余的值绝对不会用于其他任何事情.(此处的示例位于dlx1.w的第665行,或者是ctangle之后的dlx1.c的第193行.)
我的问题是:为什么Knuth这样写,而不是
nd[cc].len--;
Run Code Online (Sandbox Code Playgroud)
他确实在其他地方使用过(dlx1.w第551行):
oo,nd[k].len--,nd[k].aux=i-1;
Run Code Online (Sandbox Code Playgroud)
(而"oo"是一个类似的宏,用于递增"mems"两次 - 但这里有一些细微之处,因为.len和.aux存储在相同的64位字中.为S.len和S分配值. aux,通常只计算mems的一个增量.)
我唯一的理论是减量包括两个内存访问:首先查找,然后分配.(这是正确的吗?)这种写作方式提醒了这两个步骤.这对于Knuth来说会非常冗长,但也许这是一种本能的备忘录,而不是说教.
为了它的价值,我在没有找到答案的情况下搜索了CWEB文档.我的问题可能更多地与Knuth的标准实践有关,我正在逐渐采用.我会对这些实践被布局(并且可能被批评)作为一个块的任何资源感兴趣 - 但是现在,让我们关注为什么Knuth以这种方式编写它.
我想检查 C 中各种浮点类型可以保存的最大整数而不损失精度。这是一个测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#define FLOATTYPE long double
#define ONE ((FLOATTYPE)1.0)
#define TWO ((FLOATTYPE)2.0)
int
main(int argc,char*argv[]){
int i;
FLOATTYPE x;
x = ONE;
for(i=0;;++i){
printf("1.0<<%3d: x=%.0Lf",i,(long double)x);
if((x+ONE)!=x &&
(x+ONE)- x == ONE){
printf(" ... can increment without loss of precision\n");
}else{
printf(" ... cannot increment without loss of precision\n");
break;
}
x *= TWO;
}
printf("FLT_RADIX = %d\n",FLT_RADIX);
printf("FLT_MANT_DIG = %d\n",FLT_MANT_DIG);
printf("DBL_MANT_DIG = %d\n",DBL_MANT_DIG);
printf("LDBL_MANT_DIG = %d\n",LDBL_MANT_DIG);
printf("\nsizeof(FLOATTYPE) = %lu\n",sizeof(x));
}
Run Code Online (Sandbox Code Playgroud)
一些结果(使用gcc-9(Ubuntu 9.4.0-1ubuntu1~16.04)9.4.0): …