强基初中数学&学Python——第三十三课 二次根式计算器模块及其应用例题

    第一步、建立模块。

    把代码:

'''二次根式加、减、乘、除(除数项数不超过2)和乘方运算

 

@作者  码老师

@微信公众号  学思营 ID:xuesying

@公司  深圳五行星软件有限公司

@日期  2020-11-01

 

@使用方法

1、导入模块

>>>from quadraticradical import *

 

2、单项二次根

 

空单项二次根式(与0相等)例如:

>>>QR()

 

整数单项二次根式例如:

>>>QR(3)

 

分数单项二次根式例1:

>>>QR("1/2")

 

分数单项二次根式例2:

>>>from fractions import Fraction

>>>QR(Fraction(1, 2))

 

小数单项二次根式(字符串输入,系统自动转为分数):

>>>QR("3.14")

 

如果单项二次根式有根号数,底数在常数之后,例如

>>>QR("3.14", 10)

 

 

3、多项二次根式

 

空多项二次根式(与0相等):

>>>pr = PR()

>>>pr.pt()

 

可以有列表化单项二次根式,单项二次根式和多项二次根式参数,例如:

>>>q1 = QR("3.14", 2)

>>>p1 = PR([12, 98])

>>>_test = PR(q1, p1, QR("2/3", 10), PR(q1, [9, 8]), ["5/3", 20])

>>>_test.pt()

 

4、加多项二次根式:

>>>_test.add(["2.5", 3], PR(["7.5", 18])).pt()

 

5、减多项二次根式:

>>>_test.sub(PR(["3/2",32], ["3/4",20])).pt()

 

6、乘多项二次根式:

>>>_test.mul([1,30],[1]).pt()

 

7、除以常数:

>>>_test.div("-1/2").pt()

 

8、除以单项二次根式:

>>>_test.div(["1/2","1/10"]).pt()

 

9、除以二项二次根式:

>>>_test.div(["1/2","1/10"], ["0.125", "3.75"]).pt()

 

10、乘方:    

>>>PR([1,3],[1,2]).pow(5).pt()

 

 

'''

 

import math

from fractions import Fraction

 

 

#二次方根数类

class QR:

    '''quadratic radical'''

 

    coefficient = 0  #系数 有理数

    

    bottom = 1  #方根的底——非负有理数

    

    #相反数

    def opp(self):

        if self.coefficient != None:

           self.coefficient = -self.coefficient

        return self

 

    #倒数

    def rec(self):

        self.coefficient = Fraction(1, self.coefficient * self.bottom)

        return self

 

    #克隆

    def clone(self):

        return QR(self.coefficient, self.bottom)

    

    #打印

    def print(self, isFirst):

        if self.coefficient == None or self.coefficient == 0 or self.bottom == None or self.bottom == 0:

            return ""

        else:

            if self.coefficient == 1:

                s = ""

            elif self.coefficient == -1:

                s = "-"

            else:

                s = str(self.coefficient)

            if self.coefficient > 0:

                if not isFirst:

                    s = "+" + s

            if self.bottom != 1: 

                s += "sqrt(%d)" % self.bottom

            return s

 

    #比较大小:底降序

    #第二个要在前正值;合并0;其它负值

    def cmp(pr, otherPr):

        return otherPr.bottom - pr.bottom;

 

 

    #初始化方法

    def __init__(self, coefficient=0, bottom=1):

        #print("coefficient=",coefficient,"bottom=",bottom)

        if not isinstance(coefficient, (int, Fraction, str)) or not isinstance(bottom, (int, Fraction, str)):

            raise ValueError("输入的不是整数、分数或字符串(小数、分数)!")

        if isinstance(coefficient, (str)):

            coefficient = Fraction(coefficient)

        if isinstance(bottom, (str)):

            bottom = Fraction(bottom)

        if bottom < 0:

            raise ValueError("底数不可以小于0!")

        self.coefficient = coefficient

        self.bottom = bottom

        self.__simplestQuadraticRadical() #化简

 

    #平方方法

    def square(self):

        return self.coefficient**2 * self.bottom 

 

    #描述自己

    def __str__(self):

        if self.coefficient == 0 or self.bottom == 0:

            return "0"

        if self.bottom == 1:

            return str(self.coefficient)

        return "%ssqrt(%s)" % (str(self.coefficient), str(self.bottom))

 

    #化成最简二次根式

    def __simplestQuadraticRadical(self):

        #如果底是分数,就化为整数

        if isinstance(self.bottom, (Fraction)):

            self.coefficient = Fraction(self.coefficient, self.bottom.denominator)

            self.bottom = self.bottom.numerator * self.bottom.denominator

        return self.__firstStep()

 

    #第一步:检测自己是否是平方数,如果是就变成整数

    def __firstStep(self):

        #print("第一步:检测自己是否是平方数")

        tmp = round(math.sqrt(self.bottom))   #开方的最近整数

        if tmp ** 2 == self.bottom:

            self.coefficient *= tmp

            self.bottom = 1

            return self

        return self.__secondStep()

 

    #第二步:如果不是平方数,计算最大的可能因数

    def __secondStep(self):

        #print("第二步:如果不是平方数,计算最大的可能因数")

        maxNum = self.bottom // 2

        return self.__thirdStep(maxNum)

 

    #第三步:寻找不大于最大的可能因数的最近平方数

    def __thirdStep(self, maxNum):

        #print("第三步:寻找不小于最大的可能因数的最近平方数")

        end = math.ceil(math.sqrt(maxNum))

        return self.__fourthStep(end)

 

    #第四步:分解平方数的因数

    def __fourthStep(self, end):

        #print("第四步:分解平方数的因数")

        factors = []  #平方数是self.intNum的因数的数

        startNum = self.bottom  #开始数

        for i in range(end, 1, -1):

            i2 = i ** 2

            endNum = startNum // i2

            if i2 * endNum == startNum:

                factors.append(i)

                startNum = endNum

        return self.__fifthStep(factors, startNum)           

 

 

    #第五步:平方数因数开方成倍数,根式化成最简式

    def __fifthStep(self, factors, startNum):

        #print("第五步:平方数因数开方成倍数,根式化成最简式")

        if len(factors) == 0:

            return self     #根式已经是最简根式

        else:

            self.coefficient *= self.__getCoefficient(factors)

            self.bottom = startNum

            return self

 

    #根据因数的二次方根,生成最简根式的系数

    def __getCoefficient(self, factors):

        rst = 1

        for f in factors:

            rst *= f

        return rst

 

    #乘二次根式

    def mul(self, otherQr):

        self.coefficient *= otherQr.coefficient

        self.bottom *= otherQr.bottom

        return self.__simplestQuadraticRadical()

 

#多项二次根式

class PR:

    '''多项quadratic radical'''

 

    #项quadratic radical列表

    terms = None

 

    #克隆

    def __clone(self):

        p = PR()

        if self.terms == None or len(self.terms) == 0:

            return p

        lth = len(self.terms)

        t = []

        for i in range(lth):

            t.append(self.terms[i].clone())

        p.terms = t

        return p

 

 

    #排序合并同类项,按底数从大到小

    def __sort1(terms, idx, num):

        term = terms[num]  #需检查的元素

        for i in range(idx+1):  #把元素插入或合并到结果中

            m = terms[i]

            t = m.cmp(term)     #比较

            if t == 0:                              #合并同类项

                m.coefficient += term.coefficient                 

                return idx

            elif t > 0:                              #新的高阶项,高阶项插入当前位置

                idx += 1

                for p in range(idx, i, -1):         #后推其它项

                    terms[p] = terms[p-1]

                terms[i] = term                     #插入该项

                return idx                          #返回结果数

        idx += 1

        terms[idx] = term                           #把新项插在结果最后

        return idx

            

 

    #合并同类项与排序

    def __sort(terms):

        idx = 0   #结果下标

        lth = len(terms)

        for num in range(1, lth):

            idx = PR.__sort1(terms, idx, num)  #排序和合并1项

            #print("idx=%d" % idx)

        #消除0系数项

        temp = []

        for num in range(idx +1):

            term = terms[num]

            if term.coefficient != 0:

                temp.append(term)

        nlth = len(temp)

        if nlth == 0:

            del(terms[0:])

            return terms

        else:

            for num in range(nlth):

                terms[num] = temp[num]

            if nlth < lth:

                del(terms[nlth:])

            return terms;

 

 

    #打印自己

    def __str__(self):

        s = "原式="

        if self.terms == None or len(self.terms) == 0:

            s += "0"

        else:

            s += self.terms[0].print(True)

            for i in range(1, len(self.terms)):

                s += self.terms[i].print(False)

        return s

    def pt(self):

        print(self)

 

    #加

    def __add(self, isSub, *terms):

        if terms != None and len(terms) > 0:

            if self.terms == None:

                self.terms = []

            for term in terms:

                if isinstance(term, PR):

                    if term.terms != None and len(term.terms) > 0:

                        for t in term.terms:

                            if isSub:

                                self.terms.append(t.clone().opp())  #克隆,保证原式不受影响

                            else:

                                self.terms.append(t.clone())  

                else:

                    if isinstance(term, QR):

                        if isSub:

                            self.terms.append(term.clone().opp())     #克隆防止影响原对象

                        else:

                            self.terms.append(term.clone())     

                    else:

                        if isSub:

                            self.terms.append(QR(*term).opp())  #解包list添加1个单项式,无需克隆

                        else:

                            self.terms.append(QR(*term))  

            PR.__sort(self.terms) #排序

            

    def add(self, *terms):

        s = self.__clone()  #克隆防止改变原对象

        s.__add(False, *terms)

        return s

 

    #减            

    def sub(self, *terms):

        s = self.__clone()  #克隆防止改变原对象

        s.__add(True, *terms)

        return s

 

        

    #乘除常数,私有方法不克隆

    def __muldiv(self, fraction, isdiv):

        if self.terms != None and len(self.terms) >0:

                if isinstance(fraction,  (int, Fraction)):

                    p = fraction

                else:

                    p = Fraction(fraction)

                for term in self.terms:

                    if isdiv:

                        term.coefficient /= p

                    else:

                        term.coefficient *= p

        return self

 

 

    #多项乘单项,私有方法都不可以克隆

    def __mul(pr, qr):

        for term in pr.terms:

            term.mul(qr)

        PR.__sort(pr.terms) #排序

        return pr

 

    #乘

    def mul(self, *terms):

        if terms == None or len(terms) == 0:  #空调用返回自己

            return self

        if len(terms) == 1 and isinstance(terms[0],(int, Fraction, str)): #乘一个有理数

            return self.__clone().__muldiv(terms[0], False)      #需要克隆对象

        p = PR(*terms)  #建立要乘的多项式 如果里面有Mn或Pn,则它们会被克隆

        if self.terms == None or len(self.terms) == 0: #self是空多项式可忽略

            return p

        elif p.terms != None and len(p.terms) >0:

            lth = len(p.terms)

            s = self.__clone().__mul(p.terms[0])  #乘单项式

            if lth == 1:                             

                return s

            for i in range(lth-1):  #克隆对象乘

                s.__add(False, self.__clone().__mul(p.terms[i+1]))

            return s

        else:                       #p为空多项式

            return self;

 

            

    #乘方

    def pow(self, num):

        if not isinstance(num, (int)) or num < 2:

            print("请输入大于1的整数")

            return self

        if self.terms == None or len(self.terms) == 0:

            return self

        s = self.__clone()

        for i in range(num-1):

            s = s.mul(self)  # 由于mul会克隆,这里不用克隆

        return s

 

    #2项式倒数,使用平方差公式

    def __rec2(self):

        d = self.terms[0].square() - self.terms[1].square()  #分母

        self.terms[1].opp()                                  #第二项取相反数

        return self.__muldiv(d, True)

 

    #除

    def div(self, *terms):

        if terms == None or len(terms) == 0:  #空调用返回自己

            return self

        if len(terms) == 1 and isinstance(terms[0],(int, Fraction, str)):

            return self.__clone().__muldiv(terms[0], True)

        pq = PR(*terms)

        if pq.terms == None or len(pq.terms) == 0:

            return self

        elif len(pq.terms) == 1:

            return self.__clone().__mul(pq.terms[0].rec())

        elif len(pq.terms) == 2:                       #只处理2项式

            return self.mul(pq.__rec2())     #2项式倒数

        else:

            raise ValueError("除数多项二次根式超过了2项,超出本模块处理范围!")            

        

 

    #构造

    def __init__(self, *terms):

        if terms == None or len(terms) > 0:

            self.terms = []

            for term in terms:

                if isinstance(term, (QR)):

                    self.terms.append(term.clone())

                elif isinstance(term, (PR)):

                    if term.terms != None and len(term.terms) > 0:

                        for t in term.terms:

                            self.terms.append(t.clone())

                else:

                    self.terms.append(QR(*term)) #解包参数

                    

            PR.__sort(self.terms)  #排序合并同类项,按底数从大到小

    

   

 

 

if __name__ == "__main__":

 

    print("\n二次根式测试:")

    print("\n导入二次根式模块:")

    print('>>>from quadraticradical import *')

    print("\n构造函数测试:")

    print('>>>_qr = QR("3/2", 32)')

    print('>>>_pr = PR(["3/5", 8])')

    print('>>>_test = PR(["-3.14", 128], _qr, _pr, [4])')

    print('>>>_test.pt()')

    _qr = QR("3/2", 32)

    _pr = PR(["3/5", 8])

    _test = PR(["-3.14", 128], _qr, _pr, [4])

    _test.pt()

    print("对比")

    print('>>>_test = PR(["-3.14", 128], ["3/2", 32], ["3/5", 8], [4])')

    print('>>>_test.pt()')

    _test = PR(["-3.14", 128], ["3/2", 32], ["3/5", 8], [4])

    _test.pt()

    print("\n减多项二次根式测试:")

    print('>>>_test.sub(PR(["3/2",162], ["3/4",27])).pt()')

    _test.sub(PR(["3/2",162], ["3/4",27])).pt()

    print("\n加多项二次根式测试:")

    print('>>>_test.add(["2.5", 125], PR(["7.5", 45])).pt()')

    _test.add(["2.5", 125], PR(["7.5", 45])).pt()

    print("\n乘多项二次根式测试:")

    print('>>>_test.mul([1,2],[3, 5]).pt()')

    _test.mul([1,2],[3, 5]).pt()    

    print("\n多项二次根式除以常数测试:")

    print('>>>_test.div("-1/2").pt() ')    

    _test.div("-1/2").pt()

    print("\n多项二次根式乘方测试:")    

    print('>>>PR([1,2],[1,3]).pow(5).pt()')

    PR([1,2],[1,3]).pow(5).pt()

    print("\n多项二次根式除以一项二次根式测试:")

    print('>>>_test.div(["-1/2", 8]).pt() ')    

    _test.div(["-1/2", 8]).pt()     

    print("\n多项二次根式除以二项二次根式测试:")

    print('>>>_test.div(["-1/2", 8],[1]).pt() ')  

    _test.div(["-1/2", 8],[1]).pt()

 

复制到quadraticradical.py文件中,生成二次根式运算模块:

;运行模块无异常:

    第二步、按说明导入模块。

    第三步、按照模块的使用说明测试课本例题。

    1、二次根式    

    2、二次根式的乘除       

    3、二次根式的加减  

练习题:用二次根式计算器计算你做过的练习题,核对结果。