开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第21天,点击查看活动详情
浮点数二分
只要right - left 大于一个非常小的精度的时候,我们就认为我们得到了答案!
浮点数不存在整数取整导致的边界问题,但是会有误差,可以把精度设的高一点
// 浮点数二分算法模板
bool check(double x) {/* ... */} // 检查x是否满足某种性质
double bsearch_3(double l, double r)
{
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求 1e-6:10^-6
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;//把区间从[0~r]缩小成[0~mid]
else l = mid; //浮点数不存在整数取整导致的边界问题
}
return l;
}
求一个数的平方根
假设要求x的平方根, 答案一定在0x之间,所以在0x之间浮点数二分
- 如果 mid * mid >= x,说明再往后得到的平方就比x大了, 答案在[0,mid]区间内,把[left,right]区间更新为[0,mid]区间 , 即:right = mid
- 否则让更新区间为:[mid,right]
当精度足够小的时候就可以停止了
int main()
{
double x ;
cin >> x;
double left = 0, right = x;
while (right - left > 1e-8) //计算结果保留小数的位数
{
double mid = (left + right) / 2;
if (mid * mid >= x)
right = mid;
else
left = mid;
}
printf("%lf\n", right);
return 0;
}
写法2:直接循环100次
int main()
{
double x ;
cin >> x;
double left = 0, right = x;
for(int i = 0;i<100;i++)
{
double mid = (left + right) / 2;
if (mid * mid >= x)
right = mid;
else
left = mid;
}
printf("%lf\n", right);
return 0;
}
因为没进行一次二分,都是把区间缩小一半,所以循环100次,本质是进行100次二分,把区间长度缩小到原来的 1/2^100
上面的代码是有Bug的, x>0 ,我们是在[0,x]进行二分, 当x是小于1的时候, 比如x = 0.01, 那么就是在0~0.01里面去找答案,但是0.01求平方根的值是0.1 并不在区间里面.所以就是bug
所以答案的范围不能取在0~x 可以取成 0~ max(1,x) 也就是右边界不能<1 0~1之间的数开方之后变大了
int sqrt(int x) {
double left = 0,right = x;
double mid = 0;
while(right - left > 1e-8)
{
mid = (left+right)/2;
if(mid*mid >= x)
right = mid;
else
left = mid;
}
return right;
}
数的三次方根
给定一个浮点数 n,它的三次方根,n的范围是-10000~10000,结果保留 6 位小数
- 假设要保留n位小数,那么精度就是:1e(-n-2) 比如要保留4位小数,精度就是1e-6 也就是 10^(-6)
#include<iostream>
using namespace std;
int main()
{
double x;
cin >> x;
double left = -10000;
double right = 10000;
while(right - left > 1e-8)
{
double mid = (left+right)/2;
if(mid*mid*mid >= x) //要去左边二分
right = mid;
else
left = mid;
}
printf("%lf\n",left); //默认保留的就是6位小数
return 0;
}