偶然看见一段求根的神代码,于是就有了这篇博客;

对于求根问题,通常我们可以调用sqrt库函数,不过知其然需知其所以然,我们看一下求根的方法;

比较简单方法就是二分咯:

代码:

 #include<bits/stdc++.h>
#define MAXN 100000+10
#define MAX 100000000
#define eps 1e-6
#define ll long long
using namespace std; float get_sqrt(float x)
{
float low=, up=x, mid, now;
mid=(low+up)/;
do
{
now=mid; //**now保存上一次计算的值
if(mid*mid<x) //**mid偏小,右移
{
low=mid;
}
else //**mid偏大,左移
{
up=mid;
}
mid=(low+up)/;
}while(abs(mid-now)>eps); //**两次计算的误差小于eps,mid即为所求值
return mid;
} int main(void)
{
std::ios::sync_with_stdio(false), cin.tie(), cin.tie();
float x;
cin >> x;
cout << get_sqrt(x) << endl;
return ;
}

然而虽然其计算的结果和库函数一样,然而其效率较之库函数差数百倍,当然不是我说的神代码咯;

我们再看一下牛顿迭代法如何;

假设a为需求根的数,x为其正根,则有a=x*x;即a的正根为函数f(x)=x*x-a与x轴的正交点;

由牛顿迭代法我们可以知道,可以通过(x,f(x))的切线不断逼近解;

任取一点(x0,f(x0)),其切线方程为 y=f'(x0)*(x-x0)+f(x0),其与x轴的交点为x1=x0-f(x0)/f'(x0),x1是一个比x0更接近的近似解;

依次类推,可以求出x2,x2又比x1更接近;

可以求出x3......

由此我们得出迭代公式为:x'=x-f(x)/f'(x),再带入f(x)=x*x-a得:x'=(x+a/x)/2;

代码:

 #include<bits/stdc++.h>
#define MAXN 100000+10
#define MAX 100000000
#define eps 1e-6
#define ll long long
using namespace std; float get_sqrt(float a)
{
float x, now;
x=a;
do
{
now=x; //**now保存上一次的x值
x=(x+a/x)/; //**通过迭代更新x的值使其接近解
}while(abs(now-x)>eps); //**两次计算的误差小于eps,x即为所求值
return x;
} int main(void)
{
std::ios::sync_with_stdio(false), cin.tie(), cin.tie();
float x;
cin >> x;
cout << get_sqrt(x) << endl;
return ;
}

其效率较之二分高了很多,不过还是不如库函数;

神代码(效率为库函数的4倍):

 #include<bits/stdc++.h>
#define MAXN 100000+10
#define MAX 100000000
#define eps 1e-6
#define ll long long
using namespace std; /*float InvSqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed //**可以通过减少迭代次数来用精度换取时间
#ifndef Q3_VM
#ifdef __linux__
assert( !isnan(y) ); // bk010122 - FPE?
#endif
#endif
return 1/y;
}*/ float InvSqrt(float x)
{
float xhalf = 0.5f*x;
int i = *(int*)&x; // get bits for floating VALUE
i = 0x5f375a86- (i>>); // gives initial guess y0
x = *(float*)&i; // convert bits BACK to float
x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
// x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy //**可以通过减少迭代次数来用精度换取时间
return /x;
} int main(void)
{
std::ios::sync_with_stdio(false), cin.tie(), cin.tie();
float x;
cin >> x;
cout << InvSqrt(x) << endl;
return ;
}

其本质还是迭代法,不过因为那个魔鬼般的常数0x5f375a86 和 i = 0x5f375a86- (i>>1);中的位运算大大提高了其速度;

然而我并没有看懂,待以后继续研究;

求sqrt()底层效率问题(二分/牛顿迭代)的更多相关文章

  1. HDU.2899.Strange fuction(牛顿迭代)

    题目链接 \(Description\) 求函数\(F(x)=6\times x^7+8\times x^6+7\times x^3+5\times x^2-y\times x\)在\(x\in \l ...

  2. 二分法和牛顿迭代实现开根号函数:OC的实现

    最近有人贴出BAT的面试题,题目链接. 就是实现系统的开根号的操作,并且要求一定的误差,其实这类题就是两种方法,二分法和牛顿迭代,现在用OC的方法实现如下: 第一:二分法实现 -(double)sqr ...

  3. 牛顿迭代,多项式求逆,除法,开方,exp,ln,求幂

    牛顿迭代 若 \[G(F_0(x))\equiv 0(mod\ x^{2^t})\] 牛顿迭代 \[F(x)\equiv F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))}(mod ...

  4. 已知 sqrt (2)约等于 1.414,要求不用数学库,求 sqrt (2)精确到小数点后 10 位

    问题:已知 sqrt (2)约等于 1.414,要求不用数学库,求 sqrt (2)精确到小数点后 10 位. 出题人:阿里巴巴出题专家:文景/阿里云 CDN 资深技术专家. 考察点:基础算法的灵活应 ...

  5. Codevs 1038 一元三次方程求解 NOIP 2001(导数 牛顿迭代)

    1038 一元三次方程求解 2001年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 有形如:ax3+b ...

  6. Poj 2976 Dropping tests(01分数规划 牛顿迭代)

    Dropping tests Time Limit: 1000MS Memory Limit: 65536K Description In a certain course, you take n t ...

  7. 【leetcode】【二分 | 牛顿迭代法】69_Sqrt(x)

    题目链接:传送门 题目描述: 求Sqrt(x),返回整数值即可. [代码]: #include<bits/stdc++.h> using namespace std; ; /* int m ...

  8. 【XSY2680】玩具谜题 NTT 牛顿迭代

    题目描述 小南一共有\(n\)种不同的玩具小人,每种玩具小人的数量都可以被认为是无限大.每种玩具小人都有特定的血量,第\(i\)种玩具小人的血量就是整数\(i\).此外,每种玩具小人还有自己的攻击力, ...

  9. 【loj6538】烷基计数 加强版 加强版 Burnside引理+多项式牛顿迭代

    别问我为啥突然刷了道OI题,也别问我为啥花括号不换行了... 题目描述 求含 $n$ 个碳原子的本质不同的烷基数目模 $998244353$ 的结果.$1\le n\le 10^5$ . 题解 Bur ...

随机推荐

  1. Effective Java 读书笔记之十 序列化

    一.谨慎地实现Serializable接口 1.一旦一个类被发布,就大大地降低了“改变这个类的实现”的灵活性. 2.仔细设计类的序列化形式而不是接受类的默认虚拟化形式. 3.反序列化机制是一个“隐藏的 ...

  2. iOS开发——UI基础-按钮内边距,图片拉伸

    一.内边距 UIButton有三个属性,分别可以设置按钮以及内部子控件的内边距 1.contentEdgeInsets 如果是设置contentEdgeInsets, 会把UIImageView和UI ...

  3. 上传源码到github

    到 http://mac.github.com/ 下载 github mac客户端 然后左上角 + 号, 点击add 添加 repository(代码仓库), 然后选择已有git项目, 然后点击右上角 ...

  4. web文件操作常见安全漏洞(目录、文件名检测漏洞)

    做web开发,我们经常会做代码走查,很多时候,我们都会抽查一些核心功能,或者常会出现漏洞的逻辑.随着技术团队的壮大,组员技术日益成熟. 常见傻瓜型SQL注入漏洞.以及XSS漏洞.会越来越少,但是我们也 ...

  5. Delphi中Interface接口的使用方法

    示例注释(现在应该知道的): {   1.接口命名约定 I 起头, 就像类从 T 打头一样.   2.接口都是从 IInterface 继承而来; 若是从根接口继承, 可省略.   3.接口成员只能是 ...

  6. echarts

    ECharts,缩写来自Enterprise Charts,商业级数据图表,一个纯Javascript的图表库,可以流畅的运行在PC和移动设备上,兼容当前绝大部分浏览器(IE6/7/8/9/10/11 ...

  7. &#65279导致页面顶部空白一行解决方法

    模板文件生成html文件之后会在body开头处加入一个可见的控制符&#65279,导致页面头部会出现一个空白行.原因是页面的编码是UTF-8 + BOM. 这种编码方式一般会在windows操 ...

  8. Springmvc常用注解

    1. @RequestMapping注解的作用位置 @RequestMapping可以作用在类名上,也可以作用在方法上. 如果都有, 产生作用的路径是类名上的路径+方法上的路径. 比如Employee ...

  9. linux创建子进程--fork()方法

    (1)fork()的定义 fork()函数是Unix中派生新进程的唯一方法,声明如下: #include <unistd.h> pid_t fork(void); 我们需要理解的是,调用一 ...

  10. C++拷贝构造函数(深拷贝,浅拷贝)

    对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. #i ...