长除法计算平方根的方法总结与代码实现(C++, Python)

news2024/11/18 1:42:16

tags: DSA Math C++ Python

写在前面

之前总结了计算平方根的方法, 但是并没有给出手算方法的解释, 这次专门写一下手算方法.

据说这个方法是中国的数学家创造的, 我也没深入考证过, 总之就是非常经典了, 因为这个长除法算法(英文:Long Division Algorithm)可以计算任意精度的平方根, 也就是可以算小数点后的任意位, 下面来看看具体的方法与原理.

原理解释

代数

其实原理是基于这样一个式子:
x 2 = ( 10 a + b ) 2    ⟺    x 2 − 100 a 2 = ( 20 a + b ) b . (*) x^2=(10a+b)^2\iff x^2-100a^2=(20a+b)b.\tag{*} x2=(10a+b)2x2100a2=(20a+b)b.(*)
就是说对于一个两位数 x x x, 其平方(设其有4位)有这样的一种表示, 那么如果要计算某一个数 y = x 2 y=x^2 y=x2的平方根, 只需要通过长除法, 根据数的前面两位和后面两位迭代计算即可.

当然这样直接说显得有点不够直观, 我们举个例子, 对于 y = 6561 y=6561 y=6561, 有
  8 ,    1 8 65 , 61 64 16 1 ‾    1 , 61 ‾    1 , 61   ‾ 0 \begin{aligned} &\ \quad8,\ \ 1\\ 8&\sqrt{65,61}\\ & \quad64\\ 16\underline{1}&\quad\overline{\ \ 1,61}\\ &\quad\ \ \underline{1,61\,}\\ &\qquad\quad0 \end{aligned} 8161 8,  165,61 64  1,61  1,610

  • 首先找到前两位(不妨设为 x 1 x_1 x1, x 1 = 65 x_1=65 x1=65)的小于等于该两位数的最大整数 k k k( k ∈ [ 0 , 9 ] k\in[0,9] k[0,9]), 该数满足 k 2 ⩽ x 1 k^2\leqslant x_1 k2x1, 那么显然有 k 2 = 8 2 = 64 ⩽ 65 k^2=8^2=64\leqslant65 k2=82=6465, 这步之后, 其实就找到了商 a a a, a = k = 8 a=k=8 a=k=8.
  • 然后计算余数, 即上面公式 ( ∗ ) (*) ()中的 x 2 − 100 a 2 x^2-100a^2 x2100a2, 这个值等于 161 161 161(长除法中表现为借位),
  • 最后去找数字 b b b使得 ( 20 a + b ) b = ( 160 + b ) b ⩽ 161 (20a+b)b=(160+b)b\leqslant 161 (20a+b)b=(160+b)b161的最大的 b b b, 其中 a = 8 a=8 a=8, 也就是上面找到的商. 显然 b = 1 b=1 b=1, 可以恰好整除余数.

上面的例子中给出的是恰好整除(平方根为正整数)的情况, 那么对于不能整除的情况呢?

对于平方根为无理数的情况, 上面式子 ( ∗ ) (*) ()仍然成立, 只不过对应为余数始终不为 0 0 0, 这样一直做, 就能得到平方根了.

几何

在YouTube看到一个很不错的对于长除法的原理解释, 通过分割正方形的方法来给出直观的几何解释, 大家可以看看, 我传了B站. 長除法開方的原理(粵語中文字幕)_哔哩哔哩_bilibili;

截屏2022-12-23 21.56.50

C++实现

代码方面一开始我不太熟悉, 参考了1, 后来自己想出来了一种基于二分法的方法, 在寻找商数的时候比1的代码简洁一些, 不用遍历0~9, 效率也相对高一些.

#include <iostream>
#include <vector>
#include <iomanip>
#include <typeinfo>
using namespace std;

ostream& operator<<(ostream& os, const vector<int> v) {
    for (int i : v) os << i << " ";
    return os << endl;
}

int find_nice(int R, int b = 0) {
    int l{}, r{9};
    while (l <= r) {
        int mid = l + (r - l) / 2;
        if ((20 * b + mid) * mid > R)
            r = mid - 1;
        else
            l = mid + 1;
    }
    return l - 1;
}


long long mySqrt(long long n) {
    long long dividend{}, quotient{}, reminder{};
    int i{};
    vector<int> a(15, 0), quot{};
    // Dividing the number into segments
    while (n) {
        a[i++] = n % 100;
        n /= 100;
    }
    // i = 10;
    // a[i - 1] = 5;
    cout << a;
    for (int j = i - 1; j >= 0; --j) {
        dividend = reminder * 100 + a[j]; // update dividend
        long long tmp = find_nice(dividend, quotient);
        quot.emplace_back(tmp);
        reminder = dividend - (20 * quotient + tmp) * tmp;
        quotient = quotient * 10 + tmp;
        // cout << quotient << typeid(tmp).name() << endl;
    }
    cout << quot;
    return quotient;
}

void t1() {
    cout << mySqrt(500) << endl;  // 22
    cout << mySqrt(839) << endl;  // 28
    cout << mySqrt(1009) << endl; // 31
}
void t2() {
    cout << mySqrt(500000000000000L) << endl;
/*    2 2 3 6 0 6 7 9
    22360679
*/}

int main(int argc, char const* argv[]) {
    // t1();
    t2();
    return 0;
}

使用C++实现并不复杂, 但是却因为数值类型的位数要求, 导致结果总是会有误差的. 联想到Python强大的任意精度计算, 决定用Python来实现.

Python实现

用Python重写上面的代码, 可以得到任意精度的平方根值.

def find_nice(R, b=0):
    l, r = 0, 9
    while l <= r:
        mid = l + (r - l) // 2
        if (20 * b + mid) * mid > R:
            r = mid - 1
        else:
            l = mid + 1
    return l - 1


def mySqrt(n=0):
    dividend = quotient = reminder = 0
    a = [0] * 150
    # quot = []
    i = 150
    a[i - 1] = 5
    for j in range(i - 1, -1, -1):
        dividend = reminder * 100 + a[j]
        tmp = find_nice(dividend, quotient)
        # quot.append(tmp)
        reminder = dividend - (20 * quotient + tmp) * tmp
        quotient = quotient * 10 + tmp
    # print(quot)
    return quotient


if __name__ == '__main__':
    # print('%100.100f' % 5**.5)
    print(mySqrt())

得到的结果如下:

223606797749978969640917366873127623544061835961152572427089724541052092563780489941441440837878227496950817615077378350425326772444707386358636012153

不得不说Python的任意精度数才是数值计算的不二之选, 利用Python重写上面的程序, 重新计算根号5, 得到的值简直完美, 这里对照了oeis2给出的结果:

2.236067977499789696409173668731276235440618359611525724270897245410520

以及Python自带的求平方根函数的结果:

from math import sqrt
print('%.100f'%sqrt(5))

2.2360679774997898050514777423813939094543457031250000000000000000000000000000000000000000000000000000

发现Python自带的数值计算在20位之后就会出现误差了, 但是使用长除法就不会有误差.

ref


  1. Long Division Method to find Square root with Examples - GeeksforGeeks; ↩︎ ↩︎

  2. A002163 - OEIS; ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/111405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《ESP32》Adafruit_GFX、u8g2驱动ssd1306

本示例将使用ESP32驱动ssd1306&#xff0c;将为你介绍SSD1306&#xff0c;接线方式以及如何使用Adafruit_GFX、u8g2两种模式进行开发SSD1306。 本人踩坑了半天&#xff0c;发现Adafruit_SSD1306并不能驱动器LVGL&#xff0c;其并没有实现关键的setAddrWindow和pushColors函数用…

【网络编程】第四章 网络套接字(守护进程+TCP英译汉+TCP通协议讯流程+TCP和UDP对比)

&#x1f3c6;个人主页&#xff1a;企鹅不叫的博客 ​ &#x1f308;专栏 C语言初阶和进阶C项目Leetcode刷题初阶数据结构与算法C初阶和进阶《深入理解计算机操作系统》《高质量C/C编程》Linux ⭐️ 博主码云gitee链接&#xff1a;代码仓库地址 ⚡若有帮助可以【关注点赞收藏】…

[Java]注解

文章目录⚽ 注解的概述⚽ 常见注解的使用示例&#x1f3d0; 文档相关的注解&#x1f3d0; 在编译时进行格式检查(JDK内置的三个基本注解)&#x1f3d0; 跟踪代码依赖性&#xff0c;实现替代配置文件功能⚽ 自定义注解⚽ JDK中的元注解&#x1f3d0; Retention&#x1f3d0; Tar…

【PowerDesign】制作数据流图

目录 文章目录 前言 一、下载软件 二、使用步骤 1.打开面板 2.绘制顶层0层/数据流程图 创建加工 画出数据流向 对格式进行设置 结果展示 2. 1层数据流程图 生成子加工 框图格式设置 结果展示 注意事项 3. 2层数据流程图 总结 前言 本文以图书管理系统举例&…

java开发的环保网站垃圾分类系统源码

本项目是基于springboot开发的小区垃圾分类的监管系统。为了更好的督促小区业主更好的进行垃圾分类和垃圾投放&#xff0c;本系统设计了一套积分奖罚机制&#xff0c;如果业主此次投放垃圾符合分类要求则加10积分&#xff0c;不符合则扣除200积分&#xff0c;积分不够需要进行扫…

东北大学c++实验最后一次

【问题描述】 建立两个磁盘文件f1.txt和f2.txt&#xff0c;编写程序实现以下工作&#xff1a; &#xff08;1&#xff09;从文件in.txt输入20个整数&#xff0c;分别存放在两个磁盘文件f1.txt和f2.txt中&#xff08;每个文件中放10个整数&#xff09;&#xff1b; &#xff…

【java】java集合详解

目录一.集合类型二.集合的不同三.List解析1.ArrayList2.LinkedList3.Vector四.Set解析1.HashSet2.TreeSet3.LinkedHashSet五.Map解析1.HashMap2.TreeMap3.HashTable4.ConcurrentHashMap一.集合类型 集合类型和关系(我画的比较简略&#xff0c;其中有很多继承实现关系都没有画),…

Web入门开发【三】- 准备工作

欢迎来到霍大侠的小院&#xff0c;我们来学习Web入门开发的系列课程。 首先我们来了解下这个课程能学到什么&#xff1f; 1、你将可以掌握Web网站的开发全过程。 2、了解基础的HTML&#xff0c;CSS&#xff0c;JavaScript语言。 3、开发自己的第一个网站。 4、认识很多对编…

刷爆力扣之字符串转换整数(atoi)

刷爆力扣之字符串转换整数(atoi) HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照不同类别标签进行刷题&a…

1、移动端基础

目录1、常见浏览器PC端移动端2、手机屏幕3、移动端调试方法4、视口4.1 布局视口 layout viewport4.2 视觉视口visual viewport4.3 理想视口 idea viewport **meta视口标签5、二倍图1、物理像素和物理像素比6、多倍图7 背景缩放background-size移动端背景图展示8、移动端主流方案…

IDEA创建kotlin项目

今天新建了一个kotlin项目&#xff0c;竟然不能导入jar包&#xff0c;原因是新建项目的时候&#xff0c;选择了kotlin作为Gradle的开发语音&#xff0c;kotlin语音里面&#xff0c;下面这行配置识别不了&#xff1a; implementation fileTree(dir: libs, include: [*.jar])所以…

【蓝桥杯】第10届Scratch国赛第6题程序2 -- 捉迷藏

[导读]&#xff1a;蓝桥杯大赛是工业和信息化部人才交流中心举办的全国性专业信息技术赛事。蓝桥杯大赛首席专家倪光南院士说&#xff1a;“蓝桥杯以考促学&#xff0c;塑造了领跑全国的人才培养选拨模式&#xff0c;并获得了行业的深度认可。” 春雷课堂计划推出Scratch蓝桥杯…

青龙面板搭建+QQ机器人

搭建青龙面板首先有个服务器 我这里看到华为云有活动就入手了一个 1.系统选择 centos7.9 华为云购买地址&#xff1a;https://activity.huaweicloud.com/1212_promotion/index.html 2. 服务器上安装宝塔 yum install -y wget && wget -O install.sh http://downl…

340页11万字智慧政务大数据资源平台数据治理方案

一.1.1 数据治理子系统 建设大数据治理子平台&#xff0c;提供数据标准管理、元数据管理、数据质量管理能力&#xff0c;实现对数据的规范治理与管理&#xff1b;提供数据工厂能力&#xff0c;实现对归集的数据进行清洗、加工&#xff0c;支撑业务的数据应用需求。具体&#xf…

ES6 箭头函数 Arrow Function

前言 1. ES6 前定义函数 2. ES6 箭头函数语法 3. ES6 箭头函数返回值 4. 箭头函数中的 this 到底是谁 ? 前言 ES6 新增了一种新的函数: 箭头函数 Arrow Function 箭头函数相当于匿名函数&#xff0c;简化了函数定义&#xff0c;将原函数的 function 关键字和函数名都删掉&am…

学习.NET MAUI Blazor(三)、创建.NET MAUI Blazor应用并使用AntDesignBlazor

大致了解了Blazor和MAUI之后&#xff0c;尝试创建一个.NET MAUI Blazor应用。 需要注意的是&#xff1a; 虽然都叫MAUI&#xff0c;但.NET MAUI与.NET MAUI Blazor 并不相同&#xff0c;MAUI还是以xaml为主&#xff0c;而MAUI Blazor则是以razor为主。 这个系列还是以MAUI Bla…

23. 【gRPC系列学习】gRPC安全认证-JWT认证

JWT 即 JSON Web Token,是用 JSON 形式安全传输信息的方法。本节介绍JWT与gRPC结合,关于JWT交互流程的介绍参考文末的链接。 1. 使用JWT客户端与服务端交互 1)客户端使用用户名、密码发送给服务端 2)服务端返回JWT数据,返回数据由三部分组成 Header:TOKEN 的类型,就是JW…

截至2022年12月共计451个信息安全国家标准 汇总

写在前面 早年刚参加信息安全工作更多的学点皮毛技术&#xff0c;到处找安全工具&#xff0c;跟踪poc&#xff0c;拿到一个就全网扫一遍&#xff0c;从来没有想过&#xff0c;系统化的安全工作应该怎样搞?我做的工作在安全体系中处于哪个阶段? 后来有机会做企业安全建设&…

二本跨专业自学编程及程序员就业之路——20W社招进银行

自学编程的道路 先做个自我介绍&#xff0c;我是一名普通二本院校的学生。在广州上学&#xff0c;21年毕业&#xff0c;非科班出身。上大学之前&#xff0c;很少接触电脑&#xff0c;连QQ都是别人送我的&#xff0c;当时还开心了好一阵子。 大学的时候&#xff0c;开始接触的第…

对美国学校制度的一点儿思考

本文作者在美国生活了几十年&#xff0c;随着对这个国家的深入了解&#xff0c;发现原来对美国的一些认知上有偏差。所以其根据在美的所见所闻&#xff0c;结合中国国内的情况&#xff0c;做了分析对照&#xff0c;在此知识人网小编仅摘录关于美国学校制度的内容以飨读者。 美国…