import math # 这个函数用于检查两个数从高位起指定长度的数位是否相等,以此判断精度是否达到要求 # 参数 l 和 h 是要比较的两个数,p 表示要检查的精度位数(从小数点后开始算),len1 表示整数部分的长度 def check_precision(l, h, p, len1): """ 检查两个数l和h从高位起指定长度len1到len1 + p位是否相等,用于判断精度是否达到要求 """ # 将传入的参数l和h转换为字符串类型,方便后续按字符进行比较操作 l = str(l) h = str(h) # 如果l或者h的长度小于等于整数部分长度加上要检查的精度位数,说明还没达到要求的长度范围,直接返回False if len(l) <= len1 + p or len(h) <= len1 + p: return False # 循环遍历从整数部分长度位到整数部分长度加上精度位数的这一段数位 for i in range(len1, len1 + p): # 如果对应位置上的字符(也就是数位)不相等,说明精度还没达到要求,返回False if l[i]!= h[i]: return False # 如果循环结束都没有发现不相等的数位,说明在指定的精度范围内两个数相等,返回True,表示达到精度要求 return True # 这个函数根据给定的精度要求,对计算得到的平方根结果进行格式化输出 # 参数 x 是要输出的数值(可能是整数或者浮点数形式的平方根近似值),len1 表示其整数部分的长度,p 是要求的精度位数 def print_result(x, len1, p): """ 根据精度要求格式化输出结果 """ # 将数值x转换为字符串类型,便于后续进行字符串操作来格式化输出 x = str(x) # 如果当前数值x的总长度减去整数部分长度小于要求的精度位数p,说明小数部分的位数不够,需要补0 if len(x) - len1 < p: # 构造格式化后的字符串,先取整数部分,加上小数点,再加上原有的小数部分,最后补充足够数量的0,使其达到要求的精度位数 s = x[:len1] + "." + x[len1:] + "0" * (p - len(x) + len1) else: # 如果小数部分位数已经足够或者超过要求的精度位数,直接取整数部分、小数点以及要求精度位数的小数部分来构造输出字符串 s = x[:len1] + "." + x[len1:len1 + p] # 输出格式化后的字符串,展示符合精度要求的结果 print(s) # 这个函数使用二分法来计算给定数x的平方根,精确到小数点后p位 def binary_sqrt(x, p): """ 使用二分法计算给定数x的平方根,精确到小数点后p位 """ # 先计算x的平方根的整数部分,作为初始的近似值,后续通过二分法逐步逼近更精确的值 x0 = int(math.sqrt(x)) # 如果这个整数部分的平方恰好等于x,说明x是一个完全平方数,直接按照精度要求输出这个整数部分作为结果,然后返回,结束函数执行 if x0 * x0 == x: print_result(x0, len(str(x0)), p) return # 获取初始近似值x0的整数部分长度,用于后续判断精度以及进行相关计算时确定数位位置 len1 = len(str(x0)) # 初始化二分查找的下限为0,上限为待开方数x,后续在这个区间内通过不断二分缩小范围来逼近平方根 l = 0 h = x # 只要还没达到要求的精度,就持续进行二分查找循环 while not check_precision(l, h, p, len1): # 如果下限l不为0,说明已经开始了小数部分的二分查找过程,需要将上下限以及待开方数x的范围相应扩大 if l!= 0: h *= 10 l *= 10 x *= 100 # 计算当前区间的中间值m,作为下一次判断的候选值 m = (l + h) // 2 # 如果中间值m的平方恰好等于扩大后的待开方数x,说明找到了满足精度要求的平方根近似值,按照精度要求输出并返回结果 if m * m == x: return print_result(m, len1, p) # 如果中间值m的平方大于扩大后的待开方数x,说明平方根在左半区间,更新上限h为m elif m * m > x: h = m # 如果中间值m的平方小于扩大后的待开方数x,说明平方根在右半区间,更新下限l为m else: l = m # 如果循环结束(即达到精度要求),输出下限l对应的数值作为最终的平方根近似值(因为在二分过程中,下限l会不断逼近真实的平方根) return print_result(l, len1, p) # 这个函数使用牛顿迭代法来计算给定数x的平方根,精确到小数点后p位 def newton_sqrt(x, p): """ 使用牛顿迭代法计算给定数x的平方根,精确到小数点后p位 """ # 同样先计算x的平方根的整数部分,作为牛顿迭代法的初始近似值 x0 = int(math.sqrt(x)) # 如果这个整数部分的平方恰好等于x,说明x是一个完全平方数,直接按照精度要求输出这个整数部分作为结果,然后返回,结束函数执行 if x0 * x0 == x: print_result(x0, len(str(x0)), p) return # 获取初始近似值x0的整数部分长度,用于后续判断精度以及进行相关计算时确定数位位置 len1 = len(str(x0)) # 初始化牛顿迭代法的一个变量g为初始近似值x0,后续通过迭代公式不断更新它来逼近更精确的平方根 g = x0 # 按照牛顿迭代法的计算规则,先计算一个初始的辅助变量q,它与g共同用于后续的迭代计算 q = x // g # 根据牛顿迭代法的迭代公式,计算一次迭代后的g值,作为下一次迭代的基础 g = (g + q) // 2 # 只要还没达到要求的精度,就持续进行牛顿迭代循环 while not check_precision(g, q, p, len1): # 每次迭代时,将待开方数x的范围扩大,相当于在小数点后增加更多的数位来继续逼近更精确的结果 x *= 100 # 将当前的近似值g的范围也相应扩大,同样是为了在小数点后继续细化逼近 g *= 10 # 根据扩大后的x和g,重新计算辅助变量q,用于下一次迭代计算 q = x // g # 根据牛顿迭代法的迭代公式,再次更新g的值,使其更接近真实的平方根 g = (g + q) // 2 # 如果循环结束(即达到精度要求),按照精度要求输出最终的近似值g作为计算得到的平方根结果 return print_result(g, len1, p) # 主循环,程序会一直运行,不断接收用户输入的待开方数和精度要求,并分别使用二分法和牛顿迭代法计算平方根并输出结果 while True: # 获取用户输入的待开方数,转换为整数类型 x = int(input("请输入待开方数: ")) # 获取用户输入的精度要求,转换为整数类型 p = int(input("请输入精度: ")) # 输出提示信息,表示接下来输出的是二分法计算得到的平方根结果 print("binary_sqrt:", end="") # 调用binary_sqrt函数,使用二分法计算并输出x的平方根,精确到小数点后p位 binary_sqrt(x, p) # 输出提示信息,表示接下来输出的是牛顿迭代法计算得到的平方根结果 print("newton_sqrt:", end="") # 调用newton_sqrt函数,使用牛顿迭代法计算并输出x的平方根,精确到小数点后p位 newton_sqrt(x, p)
返回结果: