本章节对应视频

原文:

今有十八分之十二。问约之得几何?

答曰:三分之二。

又有九十一分之四十九。问约之得几何?

答曰:十三分之七。

约分

【按约分者,物之数量,不行悉全,必以分言之。分之为数,繁则难用。设有四分之二者,繁而言之,亦可为八分之四;约而言之,则二分之一也。虽则异辞,至于为数,亦同归尔。法实相推,动有参差,故为术者先治诸分。】

术曰:可半者半之。不行半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。

【等数约之,即除也。其所以相减者,皆等数之重叠,故以等数约之。】

“约分”简单来界说,便是经过核算使一个分数的分子、分母不存在除1以外的公约数。

把约分术提到的办法,按进程整理出来,便是:

1、分子、分母都是偶数的,一起除以2,重复这个进程,直到分子、分母呈现奇数;

2、分子、分母中存在奇数时,用其间较大的数减较小的数;

3、用上一步得出的差和上一步的减数进行比较,用其间较大的数减较小的数;

4、重复进程3,直到减数与差持平;

5、用进程2中的分子、分母一起除以进程4中最终得到的差,得到约分的成果。

这是咱们遇到的第一个核算进程逻辑比较复杂的问题,用表达式来描绘这个进程不太适宜,能够用伪代码来描绘。

伪代码:

约分(分子/分母){
    while(分子、分母都为偶数){
        分子/2,分母/2
    }
    if(分子、分母包括奇数){
        较小值 = 分子、分母中较小的数
        差值 = (分母-分子)绝对值
        while(较小值!=差值){
             新较小值 = 较小值、差值中较小的数
            新差值 = (较小值-差值)绝对值
            if(新较小值 = 新差值){
                公约数 = 新较小值
                跳出循环
             }
             较小值 = 新较小值
             差值 = 新差值
        }
        分子 = 分子/公约数
        分母 = 分母/公约数 
    }   
    return 分子/分母
}

接下来用实际的代码来完成这个功能。

编程言语中原生数据类型没有分数这个数据类型,咱们能够创立一个用于表示分数的类或结构体,然后以这个分数类作为输入输出的类型;更简单粗暴的办法是直接把分子、分母作为两个整型数据作为传入参数和回来值。

我这儿以包括分子、分母两个字段的json作为参数,本质便是第二种办法。

针对过错输入和特殊输入,需求进行处理。

输入中包括分子、分母的数值,所以需求判别分母不能为0。(强类型言语形参会筛选传入参数类型,不需求独自判别是否是整数,这儿就先不筛选输入是否是整数了。)分子为0时,约分成果也是0;分子等于分母时,约分成果为1。

另外,原文的核算办法没有考虑负数,咱们需求考虑关于输入负分数做处理。为了应对负分数作为参数的状况,能够在分子、分母存在奇数时求最大公约数的运算中,取绝对值进行核算,这样就不会受正负数的影响。(正负数不会影响一起除以2的操作,所以分子、分母都是偶数时,不必考虑这个问题。)前面特殊输入断定“分子等于分母”,也需求改变为“分子、分母绝对值持平”,相应处理改 为回来“分子/分母”,便是包括正负号的1。

需求代码源文件的小伙伴能够重视我的微信公众号: JianMing-95

输入:{分子,分母}

输出:{约分后的分子,约分后的分母}

基础版代码:

function chOne02(input){ //以json格局输入:分子num,分母den
    let num = input.num;
    let den = input.den;
    if(den === 0){ //筛选输入,分母不能为0
        return {"code":"001","msg":"分母不能为0,请从头输入!"};
    }
    if(num === 0){ //分子为0时,直接回来成果0
        return{"res":0};
    }
    if(Math.abs(num) === Math.abs(den)){ //分子分母绝对值持平时,直接回来成果 分子/分母(带符号的1)
        return{"res":num/den};
    }
    while(num % 2 === 0 && den % 2 === 0){ //分子、分母都是偶数时,除以2
        num = num / 2;
        den = den / 2;
    }   
    if(num % 2 !=0 || den % 2 != 0){//分子、分母包括奇数时履行下面操作
        let min = Math.abs(num) < Math.abs(den) ? Math.abs(num) : Math.abs(den); //取分子、分母中绝对值较小值储存在min中
        let dif = Math.abs(Math.abs(num) - Math.abs(den)); //核算分子、分母相减所得差的绝对值
        let divisor; //声明一个最大公约数变量divisor
        while(min != dif){ //上次减法的差和减数不持平时重复下面操作
            let newMin = min < dif ? min : dif; //把上次减法的减数和差中较小值存储在newMin中
            let newDif = Math.abs(min - dif); //核算上次减法的减数和差相减所得差的绝对值
            if(newMin === newDif){//减数和差持平时,结束循环
                divisor = newDif; //循环结束是 减数=差,是最大公约数
                break;
            }
            min = newMin;
            dif = newDif;
        }
        num = num / divisor; //分子分母除以最大公约数 取得约分后的成果
        den = den / divisor;
    }
    return {"num":num,"den":den}; //以json格局回来成果
}

调用代码及运转成果:

调用代码:
let input = {"num":49,"den":-91}; //创立输入变量
console.log(chOne02(input)); //调用办法输出成果到控制台
运转成果:
[Running] node "d:\WorkSpace\jsWork\NCMA\chOne\chOne02.js"
{ num: 7, den: -13 }
[Done] exited with code=0 in 0.14 seconds

上面约分的进程能够概括地分为两个运算:求分子、分母的最大公约数,用分子、分母一起除以最大公约数。

求最大公约数咱们在其他的当地也或许用到,所以咱们能够把求最大公约数的运算提取出来,封装为一个办法,便利后边复用。

很明显,求最大公约数的办法,输入为要求公约数的两个整数,输出为最大公约数。

约分办法输入输出不变。

约分办法:

输入:{分子,分母}

输出:{约分后的分子,约分后的分母}

求最大公约数办法:

输入:{整数1,整数2}

输出:{最大公约数}

晋级版代码:

约分办法:

function chOne03(input){ //以json格局输入:分子num,分母den
    let num = input.num;
    let den = input.den;
    if(den === 0){ //筛选输入,分母不能为0
        return {"code":"001","msg":"分母不能为0,请从头输入!"};
    }
    if(num === 0){ //分子为0时,直接回来成果0
        return{"res":0};
    }
    if(num === den){ //分子分母持平时,直接回来成果1
        return{"res":1};
    }
    let divisor = getDivisor({"num1":num,"num2":den}).divisor; //求分子、分母最大公约数
    num = num / divisor; //分子分母除以最大公约数 取得约分后的成果
    den = den / divisor;
    return {"num":num,"den":den}; //以json格局回来成果
}

求最大公约数:

function getDivisor(input){ //求最大公约数办法,以json格局传入参数,包括整数1 num1,整数2 num2
    let num1 = input.num1;
    let num2 = input.num2;
    if(num1 === 0 || num2 === 0){ //两数包括0时,最大公约数便是0
        return{"divisor":0}
    }
    if(Math.abs(num1) === Math.abs(num2)){ //两数绝对值持平时,最大公约数便是传入的整数的绝对值
        return{"divisor":Math.abs(num1)};
    }
    let divisor = 1; //声明一个最大公约数变量divisor,默认值为1
    while(num1 % 2 === 0 && num2 % 2 === 0){ //两数都是偶数时,一起除以2
        num1 = num1 / 2;
        num2 = num2 / 2;
        divisor = divisor * 2; //履行一次除以2的操作,最大公约数就乘2
    }   
    if(num1 % 2 != 0 || num2 % 2 != 0){//两数包括奇数时履行下面操作
        let min = Math.abs(num1) < Math.abs(num2) ? Math.abs(num1) : Math.abs(num2); //取两数中绝对值较小值储存在min中
        let dif = Math.abs(Math.abs(num1) - Math.abs(num2)); //核算两数相减所得差的绝对值 
        while(min != dif){ //上次减法的差和减数不持平时重复下面操作
            let newMin = min < dif ? min : dif; //把上次减法的减数和差中较小值存储在newMin中
            let newDif = Math.abs(min - dif); //核算上次减法的减数和差相减所得差的绝对值
            if(newMin === newDif){//减数和差持平时,结束循环
                divisor = divisor * newDif; //循环结束时 减数=差,这个值乘divisor是最大公约数
                break;
            }
            min = newMin;
            dif = newDif;
        }
    }
    return{"divisor":divisor};
}

调用代码及运转成果:

调用代码:
let input = {"num":49,"den":91}; //创立输入变量
console.log(chOne03(input)); //调用办法输出成果到控制台
运转成果:
[Running] node "d:\WorkSpace\jsWork\NCMA\chOne\chOne03.js"
{ num: 7, den: 13 }
[Done] exited with code=0 in 0.115 seconds