Пример #1
0
def sqrt_2_direct(decimal):
    """
    利用直接法计算2的算数平方根
    :param decimal: 自定义精度,小数点后面的数字位数
    :return: 2的算数平方根
    """
    sqrt_number = '1.'  # 算数平方根的整数部分
    # 判断当前的平方根是否满足要求
    while not judge_sqrt(sqrt_number, decimal):
        # 试错法获取下一个数字
        for i in range(1, 11):
            # 添加数字后
            new_sqrt = sqrt_number + str(i)
            # 计算乘积
            product = b_p.big_product(new_sqrt, new_sqrt)
            # 判断和2的比较结果
            compare_result = compare_number(product)
            # 如果大于2,说明上一个值是对的
            if compare_result == 1:
                sqrt_number += str(i - 1)
                break
            # 添加1-9都不大于2,说明需要添加的就是数字9
            if i == 10:
                sqrt_number += str(9)
    return sqrt_number
Пример #2
0
def sqrt_2_dichotomy(decimal):
    """
    利用二分法计算2的算数平方根,和直接法不同,此法是通过得到的乘积和2的差来判断是否终止
    :param decimal: 乘积与2的差,绝对值小于1e(-decomical)
    :return: 2的算数平方根
    """
    min_num = '0'  # 二分法开始的最小值
    max_num = '2'  # 二分法开始的最大值
    middle_num = ''  # 二分法开始的中间值
    product = '1'
    # 通过判断当前乘积和2的差是否满足条件
    while not accuracy(product, decimal):
        #  计算中间值,注意中间值的精度稍微大于decimal即可。
        # 平方根的精确位数和乘积的精确位数基本相等
        # 如果平方根的前M位是精确的,那么其平方和2的差值小数点后面连续为0的个数基本也是M个。但这并不是绝对的
        middle_num = str(
            b_d.big_division(b_s_a.big_addition(min_num, max_num), '2',
                             decimal + 5))
        # 计算乘积
        product = b_p.big_product(middle_num, middle_num)
        # 判断大小
        compare_result = compare_number(product)
        if compare_result == 1:
            # 大值变小
            max_num = middle_num
        elif compare_result == -1:
            # 小值变大
            min_num = middle_num
    return middle_num, product
Пример #3
0
 def s_dichotomy(self):
     """
     利用二分法计算算数平方根
     :return: 最终的结果
     """
     min_num = '0'  # 二分法开始的最小值
     max_num = '4'  # 二分法开始的最大值
     middle_num = '2.'  # 二分法开始的中间值
     # 判断当前解是否满足条件,保证正确性,此时多保留几位
     if self.s == 'p':
         leave_count = self.d + self.l + self.change
     elif self.s == 's':
         leave_count = self.d + self.l + self.change + self.add
     # 依然是根据精度判断
     while not self.control_p(middle_num, leave_count):
         # 注意因为中间值的精确度小的话,会导致每次的middle_num 不变,因此下面的精度要稍微大点
         middle_num = str(
             b_d.big_division(b_s_a.big_addition(min_num, max_num), '2',
                              leave_count * 3))
         # 计算乘积
         product = b_p.big_product(middle_num, middle_num)
         # 判断大小
         compare_result = self.compare_number(product)
         if compare_result == 1:
             # 大值变小
             max_num = middle_num
         elif compare_result == -1:
             # 小值变大
             min_num = middle_num
         else:
             return self.get_result(middle_num, self.s)
     return self.get_result(middle_num, self.s)
def get_carry(str_a, str_b):
    """
    计算该位可以取的商值
    :param str_a: 该位的被除数
    :param str_b: 除数
    :return: 可以取的商值
    """
    for i in range(1, 11):
        product = b_p.big_product(str(i), str_b)
        if compare_number(str_a, product) == -1:
            return str(i - 1)
        elif compare_number(str_a, product) == 0:
            return str(i)
    return print('被除数' + str_a, '除数' + str_b, '计算商出现错误')
Пример #5
0
def sqrt_2_sequence(decimal):
    """
    构造数对。数对元素之间的商值看作根号2的近似。
    和二分法、牛顿迭代法相同,此法也是通过得到的乘积和2的差来判断是否终止
    :param decimal: 小数的精度
    :return:
    """
    # 初始数对
    s = ['1', '1']
    # 初始比值
    radio = '1'
    # 乘积
    product = '1'
    # 通过判断当前乘积和2的差是否满足条件
    while not accuracy(product, decimal):
        c_s = s.copy()
        # 构造下一个数对
        s[0] = b_s_a.big_addition(c_s[0], c_s[1])
        s[1] = b_s_a.big_addition(str(b_p.big_product('2', c_s[0])), c_s[1])
        # 计算比值,保留位数也要比decimal稍微大点
        radio = str(b_d.big_division(s[1], s[0], decimal + 5))
        # 计算乘积
        product = b_p.big_product(radio, radio)
    return radio, product
Пример #6
0
 def control_p(self, s_d, decimal):
     """
     s_d的平方与转换后的开方的数之间的差值绝对值不大于1e(-decimal)
     :param s_d: 需要判断的对象,代表平方根
     :param decimal: 差的精度要求
     :return: 不满足返回False,满足返回True
     """
     # 首先计算平方
     squre = b_p.big_product(s_d, s_d)
     # 然后计算差值
     sub = b_s_a.big_subtraction(squre, self.n)
     # 如果是负数,去掉负号
     if sub[0] == '-':
         sub = sub[1:]
     # 因为是比较大小
     if '.' not in sub:
         sub += '.0'
     # 开始比较大小
     d_index = sub.index('.')
     if d_index > 1:  # 因为1e(-decimal)整数部分只有一位1.0,0.1,0.01,0.001……等等
         return False
     elif d_index == 1:
         if int(sub[0]) > 1:
             return False
         elif int(sub[0]) == 1:
             if decimal != 0:
                 return False
             else:  # 和1.0比较大小
                 if list(set(sub[2:])) == ['0']:
                     return True
                 else:
                     return False
         else:
             if decimal == 0:
                 return True
             # 考虑到需要开方的数,可能比较小,此时精度要在这个的基础上更小。
             # 也就是对于0.0002,0.05这样的整数部分为0的,计算其小数点后面连续为0的个数
             # 判断小数点后连续为0的个数
             count_zero = 0  # 判断差值中小数点之后,连续为0的个数
             for h in sub[2:]:
                 if h != '0':  # 只要出现其他的数字,就判断连续为0的个数是否满足需求的精度
                     if count_zero >= self.l + decimal + self.change:  # 需要加上开方的数原来自身的精度或者
                         return True
                     else:
                         return False
                 else:  # 小数点出现后,只要为0就开始加1
                     count_zero += 1
Пример #7
0
def sqrt_2_newton(decimal):
    """
    利用牛顿迭代f计算2的算数平方根,和二分法相同,此法也是通过得到的乘积和2的差来判断是否终止
    :param decimal: 乘积与2的差,绝对值小于1e(-decomical)
    :return: 2的算数平方根
    """
    start_num = '1'
    product = '1'
    # 通过判断当前乘积和2的差是否满足条件
    while not accuracy(product, decimal):
        # a = (a + (2/a)) /2
        # 保留位数也要比decimal稍微大点
        start_num = b_d.big_division(
            b_s_a.big_addition(start_num,
                               b_d.big_division('2', start_num, decimal + 5)),
            '2', decimal + 5)
        # 计算乘积
        product = b_p.big_product(start_num, start_num)

    return start_num, product
Пример #8
0
    def s_direct(self):
        """
        利用直接法获得平方根,
        :return: 字符串形式的算数平方根
        """
        # 首先确定整数位上的数字
        first_n = int(self.n[0])
        if first_n == 9:
            start_n = '3.'
        elif 4 <= first_n < 9:
            start_n = '2.'
        elif 1 <= first_n < 4:
            start_n = '1.'
        else:
            start_n = '0.'

        # 判断当前解是否满足条件,保证正确性,此时多保留几位
        while not eval('self.control_%s' % self.s)(
                start_n, self.l + self.d + self.change):
            # 试错法获取下一个数字
            for i in range(0, 11):
                # 添加数字后
                new_sqrt = start_n + str(i)
                # 计算平方
                product = b_p.big_product(new_sqrt, new_sqrt)
                # 比较结果
                compare_result = self.compare_number(product)
                # 如果大于,说明上一个值是对的
                if compare_result == 1:
                    start_n += str(i - 1)
                    break
                elif compare_result == 0:
                    return self.get_result(new_sqrt, self.s)
                # 添加1-9都小于,说明需要添加的就是数字9
                if i == 10:
                    start_n += str(9)
        return self.get_result(start_n, self.s)
def big_division(a, b, decimal):
    """
    任意实数的除法
    :param a: 任意实数
    :param b: 任意实数
    :param decimal: 结果中保留的小数位数.最后一位数字不进行任何形式的近似。
    对于整除的情况,商值得小数位数如果小于decimal,则不受decimal的限制。如果大于则依然遵循decimal的限制
    :return: 自定义精度的商值
    """
    if a == b:
        return 1  # 不受decimal的限制

    # 判断结果的符号
    sign = ''
    if a[0] == '-':
        a = a[1:]
        if b[0] != '-':
            sign = '-'
        else:
            b = b[1:]
    else:
        if b[0] == '-':
            b = b[1:]
            sign = '-'

    # 获取实数的小数点位数
    decimal_a = 0
    if '.' in a:
        decimal_a = len(a) - a.index('.') - 1
        a = a.replace('.', '')

    decimal_b = 0
    if '.' in b:
        decimal_b = len(b) - b.index('.') - 1
        b = b.replace('.', '')

    # 最长的小数位数
    max_de = max(decimal_a, decimal_b)

    # 两个数转为整数
    if max_de:
        a += '0' * (max_de - decimal_a)
        b += '0' * (max_de - decimal_b)

    # 将两个数前面的0去掉
    new_a = ''
    for i in range(len(a)):
        if a[i] != '0':
            new_a = a[i:]
            break
    new_b = ''
    for j in range(len(b)):
        if b[j] != '0':
            new_b = b[j:]
            break

    if new_a == '':
        return '0'
    if new_b == '':
        return print('WARNING:商不能为0')

    # 被除数放大添加的0的个数
    add_0 = 0

    # 如果被除数小于除数,则需要将被除数放大倍数,
    if compare_number(new_a, new_b) == -1:
        add_0 = len(new_b) - len(new_a) + 1  # 保证被除数一定大于除数,被除数比除数多一位
        new_a += '0' * add_0

    # a和b只是小数点位置不同,其他的数字是相同的。也就是说b是a的整数倍
    if add_0:
        if new_a == new_b + '0':
            return '0.' + '0' * (add_0 - 2) + '1'

    # 判断开始对应的位置
    start_carry = 0
    for c in range(len(new_a) + 1):
        if compare_number(new_a[:c], new_b) >= 0:
            start_carry = c - 1
            break

    # 该为对应的被除数
    if start_carry == 0:
        dividend = ''
    else:
        dividend = new_a[:start_carry]

    # 下面进行竖式模拟的除法
    div = ''  # 存储商的结果

    while not judge(div, decimal):  # 这么设置,会导致后面出现为数字0,这种情况后面再处理

        try:
            # 当前的被除数为
            dividend = dividend + new_a[start_carry]
            # 当前位的被除数不小于除数,才可以计算商
            if compare_number(dividend, new_b) >= 0:
                # 此位获得的商
                current_num = get_carry(dividend, new_b)
                # 存储商
                div += current_num
                # 计算差值
                dividend = b_s.big_sub_add(dividend,
                                           b_p.big_product(current_num, new_b),
                                           '-')
            else:
                # 此时需要借位
                div += '0'

            start_carry += 1
            if dividend == '0':
                dividend = ''

        except IndexError:
            # 当start_carry超过new_a的长度时,此时需要就要加小数点,以及加0
            if '.' not in div:
                div += '.'
            # 当前的被除数为
            if dividend:
                dividend = dividend + '0'

            # 当前位的被除数大于除数,才可以计算商
            if compare_number(dividend, new_b) >= 0:
                # 此位获得的商
                current_num = get_carry(dividend, new_b)
                # 存储商
                div += current_num
                # 计算差值
                dividend = b_s.big_sub_add(dividend,
                                           b_p.big_product(current_num, new_b),
                                           '-')
            else:
                # 此时需要借位
                div += '0'

            if dividend == '0':
                dividend = ''

    # 如果被除数添加过数字0,此时需要恢复
    if add_0:
        # 首先获的小数点的位置
        de_index = div.index('.')
        # 去除小数点
        div = div.replace('.', '')

        # 如果小数点前面的数字多于add_0
        if de_index > add_0:
            result_div = div[:(de_index - add_0)] + '.' + div[(de_index -
                                                               add_0):]
        elif de_index == add_0:
            result_div = '0.' + div
        else:
            result_div = '0.' + '0' * (add_0 - de_index) + div
    else:
        result_div = div

    #  对得到的结果进行规范化处理,需要将数字最后的0去掉
    for c in range(len(result_div) - 1, 0, -1):
        if result_div[c] == '.':
            result_div = result_div[:(c + 1)] + '0'
            break
        elif result_div[c] != '0':
            result_div = result_div[:(c + 1)]
            break

    # 添加符号
    result_div = sign + result_div

    return result_div