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)2⟺x2−100a2=(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,61​0​

  • 首先找到前两位(不妨设为 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 k2⩽x1​, 那么显然有 k 2 = 8 2 = 64 ⩽ 65 k^2=8^2=64\leqslant65 k2=82=64⩽65, 这步之后, 其实就找到了商 a a a, a = k = 8 a=k=8 a=k=8.
  • 然后计算余数, 即上面公式 ( ∗ ) (*) (∗)中的 x 2 − 100 a 2 x^2-100a^2 x2−100a2, 这个值等于 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)b⩽161的最大的 b b b, 其中 a = 8 a=8 a=8, 也就是上面找到的商. 显然 b = 1 b=1 b=1, 可以恰好整除余数.

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

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

几何

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

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;elsel = 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 segmentswhile (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 dividendlong 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;  // 22cout << mySqrt(839) << endl;  // 28cout << mySqrt(1009) << endl; // 31
}
void t2() {cout << mySqrt(500000000000000L) << endl;
/*    2 2 3 6 0 6 7 922360679
*/}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, 9while l <= r:mid = l + (r - l) // 2if (20 * b + mid) * mid > R:r = mid - 1else:l = mid + 1return l - 1def mySqrt(n=0):dividend = quotient = reminder = 0a = [0] * 150# quot = []i = 150a[i - 1] = 5for 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) * tmpquotient = quotient * 10 + tmp# print(quot)return quotientif __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; ↩︎

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

  1. 计算相机投影矩阵(含代码)(Python)

    计算相机投影矩阵(含代码)(Python) 前几天处理点云时,需要使用到像片与3D点云的对应关系.在这边找了一圈没有发现直接可用的代码,于是去GitHub试了一下,以下是一个提炼后的矩阵计算代码. 下 ...

  2. python计算时间差的方法_如何计算时间差,用Python算法的话

    这篇文章主要介绍了python计算时间差的方法,实例分析了Python时间操作的相关模块与技巧,需要的朋友可以参考下 本文实例讲述了python计算时间差的方法.分享给大家供大家参考.具体分析如下: ...

  3. java bigdecimal 开方_JAVA BigDecimal使用牛顿迭代法计算平方根(开方)

    Java中虽然可以用Math.sqrt获得某值的平方根,但是该值必须是double类型的.可是有些项目对数值精度要求比较高,我们一般会用BigDecimal来存储,BigDecimal并不提供计算平方 ...

  4. shell怎么把负数变成正数_excel怎么计算平方根-记住简单的收藏复杂的

    在excel中,有四百多个函数,如果再组合应用那就成千上万个,具体多少别再纠结了,香哥只想表明一个问题,简单的好记又常用的就记住,复杂的不常用的找到好的使用文章就收藏了,这样才能提高工作效率. exc ...

  5. python求平方根的代码_Python求解平方根的方法

    本文实例讲述了Python求解平方根的方法.分享给大家供大家参考.具体如下: 主要通过SICP的内容改写而来.基于newton method求解平方根.代码如下: #!/usr/bin/python ...

  6. 计算平方根的一些方法总结(C++)

    tags: DSA Math C++ 写在前面 重新熟悉下计算平方根的算法, 当然对于力扣的平方根69. x 的平方根 - 力扣(LeetCode), 已经出现了不下五种的方法了, 这次简要总结下. ...

  7. python求解平方根的方法_Python分享解平方根的方法 python代码改错,关于逐次逼近和分享平方根...

    Python如何使用平方根?所谓喜欢,不过是不清醒时的一种错觉.小编喜欢这种错觉.有那么一瞬间,小编想和你在一起,一辈子. 用Python分享一个数的平方根. At each iteration (l ...

  8. ML之相似度计算:图像数据、字符串数据等计算相似度常用的十种方法简介、代码实现

    ML之相似度计算:图像数据.字符串数据等计算相似度常用的十种方法简介.代码实现 目录 相似度 1.余弦相似性-夹角余弦(Cosine_Distance)距离 2.代码实现-余弦距离.余弦相似度 2.皮 ...

  9. python中math计算平方根的函数_Python中利用sqrt()方法进行平方根计算的教程

    Python中利用sqrt()方法进行平方根计算的教程 这篇文章主要介绍了Python中利用sqrt()方法进行平方根计算的教程,是Python学习的基础知识,需要的朋友可以参考下 sqrt()方法返 ...

最新文章

  1. 2021年春季学期-信号与系统-第十五次作业参考答案-第十小题参考答案
  2. 这样学习正则表达式就轻松了!
  3. 系统架构设计师证书含金量_计算机专科生不能错过的两个证书,含金量比较高,出社会有益...
  4. java里怎么存入数据并进行排序_Java数据结构之排序---插入排序
  5. C++中lib和dll解析
  6. MS SQL 2008认证考试大纲
  7. 地铁线路图的设计与实现
  8. 《设计模式解析(第2版•修订版)》—第2章 2.4节类图
  9. 老旗舰华为能用上鸿蒙吗,荣耀手机能升级鸿蒙吗?五款旗舰优先,老荣耀机主或有惊喜...
  10. 蚂蚁金服OceanBase“击败”甲骨文?呵呵!
  11. python 微信扫码登录_python实现微信第三方网站扫码登录(Django)
  12. xfce实现桌面图标透明
  13. 解决问题最重要的习惯不是一直盯着屏幕和编写修改代码,某些时候,阻止你成功的东西恰恰会是过于努力。这时候你需要暂停一下,平缓你的思绪,换一种方法或许能带给你不一样的效果。
  14. css淡入动画,使用CSS淡入大动画效果
  15. anaconda的默认位置修改pkgs以及默认创建环境踩坑
  16. 多进程和多线程的使用场景
  17. 网易云音乐关键字搜索并生成下载url
  18. 我是如何学习Java的~标志寄存器及其应用
  19. 红旗linux 输入法问题,红旗Linux牵手搜狗输入法 带给用户无拘无束输入体
  20. linux stlport 编译,VC++2010下编译STLport,Boost

热门文章

  1. python - 密码加密与解密
  2. 如何解决word文档损坏打不开呢?
  3. esp32的智能遥控
  4. matlab仿真超声波测距,汽车倒车雷达的Simulink仿真测试
  5. 案例分享|国内某大行澳门分行数据平台案例
  6. 自我介绍以及未来规划
  7. 西安城的智慧,西安人的欢歌
  8. 20155314 2016-2017-2 《Java程序设计》第6周学习总结
  9. Justice 结构体记录排序前下标
  10. 船桨数学模型matlab,船用螺旋桨负载特性数字仿真