likes
comments
collection
share

JAVASCRIPT遇到《九章算术》-卷第一 方田 (1)方田、里田

作者站长头像
站长
· 阅读数 2

B站视频链接

小伙伴们大家好啊。

我们从这一章节开始解读正文部分的内容,先看标题。

原文:

卷第一 方田

魏 刘徽 注

唐朝议大夫行太史令上轻车都尉臣李淳风等奉敕注释

方田【以御田畴界域】

《九章算术》第一卷标题“方田”,根据注解“以御田畴界域”,说明《方田》这一卷的内容是用于界定田地的范围。范围就是面积和周常,由此可知方田这一卷应该主要涉及面积、长度的计算。

原文:

今有田广十五步,从十六步[1]。问为田几何?

答曰:一亩。

又有田广十二步,从十四步。问为田几何?

答曰:一百六十八步。【图从十四,广十二。[2]】

方田

术曰:广从步数相乘得积步。

【此积谓田幂。凡广从相乘谓之幂。】

【臣淳风等谨按:经云广从相乘得积步,注云广从相乘谓之幂,观斯注意,积幂义同。以理推之,固当不尔。何则?幂是方面单布之名,积乃众数聚居之称。循名责实,二者全殊。虽欲同之,窃恐不可。今以凡言幂者据广从之一方;其言积者举众步之都数。经云相乘得积步,即是都数之明文。注云谓之为幂,全乖积步之本意。此注前云积为田幂,于理得通。复云谓之为幂,繁而不当。今者注释,存善去非,略为料简,遗诸后学。】

以亩法二百四十步除之,即亩数。百亩为一顷。

【臣淳风等谨按:此为篇端,故特举顷、亩二法。余术不复言者,从此可知。一亩田,广十五步,从而疏之,令为十五行,即每行广一步而从十六步。又横而截之,令为十六行,即每行广一步而从十五步。此即从疏横截之步,各自为方。凡有二百四十步。为一亩之地步数正同。以此言之,即广从相乘得积步,验矣。二百四十步者,亩法也。百亩者,顷法也。故以除之,即得。】

今有田广一里[3],从一里。问为田几何?

答曰:三顷七十五亩。

又有田广二里,从三里。问为田几何?

答曰:二十二顷五十亩。

里田

术曰:广从里数相乘得积里。以三百七十五乘之,即亩数。

【按此术,广从里数相乘得积里。方里之中有三顷七十五亩,故以乘之,即得亩数也。】

注释:

【1】广:宽。从:长。

【2】刘徽注图已经遗失,李潢《九章算术细草图说》中的补图如图。

【3】1里=300步。

JAVASCRIPT遇到《九章算术》-卷第一 方田 (1)方田、里田

我们看到方田、里田,这两个问题类型本质都是求方形田地面积的问题,只是单位换算上有区别。也是因此,我把这两部分放在一个章节来讲。

方田部分。

由于涉及单位比较多,这里涉及了一个长度单位“步”,三个面积单位“步”“亩”“倾”。

我们先来理清单位换算关系。面积单位“步”,根据原文说法,是长一步宽一步的方形的面积,以现代人习惯,应该称为“平方步”,为了区分,后面也称面积单位“步”为“平方步”。因为这里是书的开头,所以介绍了一下换算关系。根据方田术中提到“以亩法二百四十步除之,即亩数。百亩为一顷。”,可以得出单位换算关系:1亩=240平方步,1顷=100亩。

接下来我们来看求面积方法,原文“方田术曰:广从步数相乘得积步。”,可知宽度步数乘长度步数得出面积的(平方)步数。(实际上就是小学最开始接触到的基础乘法,加上一个面积单位换算。)

里田部分。

这里说的“里田”,按我个人的理解,就是边长以“里”为单位的(方形)田地。这里同样涉及一个长度单位“里”和面积单位“里”,同理面积单位“里”应该称为“平方里”。

根据“里田术曰:广从里数相乘得积里。以三百七十五乘之,即亩数。”,很容易理解宽度里数乘长度里数得出面积(平方)里数。后面又告诉我们,平方里数乘375就能得到亩数,但是没告诉我们为什么,注解中也没有说明。

这里就涉及到一个单位换算关系的隐藏知识,原文中没有提到的“里”和“步”的换算,应该是1里=300步。结合方田中说明的换算关系,1平方里=300步*300步=90000平方步=90000/240亩=375亩,这样就得到了“平方里”和“亩”之间的换算关系。(我猜注解没有提到换算关系,是因为做注解时也是1里=300步,与原文中没有差异,不会产生理解障碍。)

在理解了“面积=宽*长”和长度单位、面积单位换算关系后,就很容易理解原文中的四个问题了:

(1)今有田广十五步,从十六步。问为田几何? 答曰:一亩。

15 * 16 = 240平方步 = 1亩

(2)又有田广十二步,从十四步。问为田几何? 答曰:一百六十八步。

12 * 14 = 168平方步

(好吧,这个问题连单位换算都没有。)

(3)今有田广一里,从一里。问为田几何? 答曰:三顷七十五亩。

1 * 1 = 1平方里 * 375亩/平方里 =(375亩)/(100亩/顷)= 3顷75亩

(4)又有田广二里,从三里。问为田几何? 答曰:二十二顷五十亩。

2 * 3 = 6平方里 * 375亩/平方里 =(2250亩)/(100亩/顷)= 22顷50亩

虽然这几个问题在理解单位换算关系后,基于我们现有的知识体系,都是很简单的问题。但是不能否认的是,这确实是基于实际应用产生的问题。所以当我们也本着解决实际问题的心态,来用代码实现《九章算术》中的“术”,或许会有不同的收获。

因为方田术、里田术,都是整数乘法相关的问题,所以我准备使用同一个函数来实现这两部分内容涉及的计算。

显然,需要的输入是田地的长和宽,返回值是田地的面积。

我来说一下我的分析过程:

核心计算是“面积=长*宽”,实现很简单,比较复杂的是需要考虑到单位换算问题。输入需要判断以“里”为单位,还是以“步”为单位;输出需要换算为“XX顷XX亩XX平方步”的形式。

我们依旧采用json作为输入输出。

输入:包含四个字段{长度里数,长度步数,宽度里数,宽度步数}。

输出:包含三个字段{面积顷数,面积亩数,面积平方步数}。

先把输入的长宽统一为以“步”为单位,计算出以“平方步”为单位的面积,再换算为“XX顷XX亩XX平方步”的形式。

计算过程:

总长度步数 = 长度里数 * 300 + 长度步数

总宽度步数 = 宽度里数 * 300 + 宽度步数

总面积平方步数 = 总长度步数 * 总宽度步数

面积顷数 = (总面积平方步数 /(240 * 100))取整

面积亩数 = ((总面积平方步数 %(240 * 100))/ 240)取整

面积平方步数 = (总面积平方步数 %(240 * 100))% 240

【注】:“%”是取余数的操作,A%B就是求A除以B的余数。

理清了计算过程,还需要考虑一下错误处理,提高代码的健壮性。这里只涉及整数乘法,暂时不用考虑输入小数的问题。我们要计算的是土地面积,所以有约束条件,长宽都必须是正整数,即需要同时满足下面条件:

长度里数<0 || 长度步数<0 || 宽度里数<0 || 宽度步数<0 为假

长度里数>0 || 长度步数>0 为真

宽度里数>0 || 宽度步数>0 为真

【注】:“&&”表示与逻辑关系,“||”表示或逻辑关系,“!”表示非逻辑关系。

接下来把这个计算过程转换为代码。

输入:{长度里数,长度步数,宽度里数,宽度步数}

输出:{面积顷数,面积亩数,面积平方步数}

代码:

function chOne01(input){//以json格式输入:长度里数lenLi,长度步数lenStep,宽度里数widLi,宽度步数widStep
    let lenLi = input.lenLi;
    let lenStep = input.lenStep;
    let widLi = input.widLi;
    let widStep = input.widStep;

    if(lenLi < 0 || lenStep < 0 || widLi < 0 || widStep < 0){ //过滤错误输入
        return {"code":"001","msg":"长宽不能为负数,请重新输入"};
    }
    if(!(lenLi > 0 || lenStep > 0)){
        return {"code":"002","msg":"长度不能为0,请重新输入"};
    }
    if(!(widLi > 0 || widStep > 0)){
        return {"code":"003","msg":"宽度不能为0,请重新输入"};
    }


    length = lenLi * 300 + lenStep; //把长度换算为以步为单位
    width = widLi * 300 + widStep; //把宽度换算为以步为单位
    area = length * width; //计算以平方步为单位的面积
    let qing = Math.floor(area / (100 * 240)); //计算面积顷数
    let mu = Math.floor((area % (100 * 240)) / 240); //计算面积亩数
    let step = (area % (100 * 240)) % 240; //计算面积平方步数
    return {"qing":qing,"mu":mu,"step":step}; //以json格式返回结果
}

调用代码及运行结果:

let input = {"lenLi":1,"lenStep":1,"widLi":1,"widStep":1}; 
console.log(chOne01(input)); //调用方法在控制台输出结果

运行结果:
PS D:\WorkSpace\JSWork\test> node "d:\WorkSpace\JSWork\test\chOne01.js"
{ qing: 3, mu: 77, step: 121 }