double x;

scanf(“%lf",&x);

double cube;

暂且把输入的数命名为x,所求立方根为cube,要求精度为3位小数。我们来写一段代码求出它的立方根。之前已经说过,牛顿已经给出了一个对数阶计算量的算法:二分法。

我们先来建立基本步骤。

1.认识步骤

二分法的步骤是什么?我们先自己在脑海中运行一下,比如求20的立方根:先猜20,大了;猜10,大了;猜5,大了;猜2.5,小了——就猜它和上一个数的平均数,(2.5+5)/2,3.75;3.75又大了,猜它和上一个数的平均数...

容易归纳出,我们从x开始猜,假如大了,就猜它的一半,假如小了,就猜它和它上一个数的平均数。并且之后都猜它和它上一个数的平均数。

真的是这样吗?

假如一开始是“小”呢?

ok,我们再写一个if分支,如果第一个是大,那么就像上面那样猜。如果第一个是小,那么就反过来。

看起来算法框架就此确定了。

可是,“第一次和上一个判断不同的判断”,用人的思维很好理解,简简单单,一眼看穿。但,对人简单的事情,对计算机不一定简单。为了实现这个功能,我们还得引入一个变量,姑且将它命名为int Is;每次cube的立方和x的差值,姑且命名为double margin;

Is=(x>cube*cube*cube);

如果猜小了,Is的值为1,猜大了就为0(等于就直接输出)

为了记录上一个判断,我们还得定义一个变量,姑且命名为int lastIs;每次循环末尾,lastIs=Is,把Is赋给lastIs,这样就存储了上一个Is的值,再从第二次循环开始的每次循环开头,进行一个Is和lastIs是否相等的判断,如果是,进行某些步骤,如果不是,进行另外一些步骤...

确实能运行,但这是否太麻烦了?我们要一开始就写两个分支,再两个分支中又分支——并且这些分支的步骤还大同小异,仅仅因为要与上一次循环比对,就得重新分支,并且加上一堆复杂的判断。

我们能不能把它统一起来呢?

2.优化步骤并实现算法

再次观察,我们可以发现,大了猜小,小了猜大,逐步逼近,这个像什么?

像不像是两个值,一个是上限,一个是下限,它们逐渐往中间某个值靠拢,把它“夹”出来?

是的,想到这一点,我们就摆脱了上一个循环的桎梏,不用再些那一大堆分支。

我们定义出上限和下限double max,min;再函数最初,默认max=x,min=0——假如x是负数的话就让x=-x,把x变成正数。为此我们引入一个变量int is,假如x为正数is=1,假如x为负数is=-1——引入一个数来记录状态是编程中非常常用的手法,再求得正cube之后,我们最后再乘一次is,就能得到真正的cube了。接下来就只用考虑x为正的情况。

假如猜的cube大了,那么max=cube,小了,min=cube,这样,通过一个简单的分支,就能实现基本步骤。

步骤已经完善了,接下来就是具体的代码实现、精度控制问题。

需要三位小数,我们可以定义一个误差量double margin,它是cube的立方与x的差值。很容易知道,只要循环的终止条件是margin在(-0.001,0.001)区间内,我们就能让cube的误差小于0.001.

于是代码如下:

int main() {double x;scanf("%lf", &x);int is = 1;if (x < 0) {is = -1;x = -x;}double cube = x, max = x, min = 0;double margin = cube * cube * cube - x;while (1) {if (margin >= 0.001 || margin <= -0.001) {cube = (max + min) / 2;} else {break;}margin = cube * cube * cube - x;if (margin >= 0.001) {max = cube;} else if (margin <= -0.001) {min = cube;}}cube = cube * is;printf("%f", cube);return 0;
}

3.代值测试并纠正算法

看起来一切都完美了,真的是这样吗

我们测试一下。

输入-5,输出-1.709900;输入27,输出2.999989;输入-4096,输出-16.000000;输入0,输出0.000000;输入-1,输出-1.000000。负数没问题,正数没问题,大数没问题,0没问题,1也没问题,精度没问题,看起来不错。

错了。

输入0.125——程序没有任何输出,进入调试,发现程序陷入了死循环。

是的,我们从x开始猜,上限为x,下限为0,可是,如果cube本就不在这个默认的区间里呢?假如x绝对值小于1,我们知道,|cube|是大于|x|的,根据我们的程序,就求不到结果了。而达不到循环终止条件,程序自然不会进行任何输出,而且陷入死循环,占用CPU资源。

还是我们上一篇说的,一定要确定程序能达到循环终止条件,或者中途有break跳出循环。

于是我们以1为分界线,再加一个分支,解决|x|<1问题。

完美

#include <stdio.h>int main() {double x;scanf("%lf", &x);int is = 1;if (x < 0) {is = -1;x = -x;}double cube = x, max, min;if (x < 1) {max = 1;min = x;} else {max = x;min = 1;}double margin = cube * cube * cube - x;while (1) {if (margin >= 0.001 || margin <= -0.001) {cube = (max + min) / 2;} else {break;}margin = cube * cube * cube - x;if (margin >= 0.001) {max = cube;} else if (margin <= -0.001) {min = cube;}}cube = cube * is;printf("%f", cube);return 0;
}

4.数学分析

完美?

通过数学方法我们知道,(x+0.001)^3=x^3+0.003x^2+0.000003x+0.000000001

margin=0.003cube^2+0.000003cube+0.000000001

(x+d)^3=x^3+3dx^2+3xd^2+d^3

对比易得,通过margin<0.001让精度误差d<0.001,前提条件是|x|>1,而在|x|<1的时候,算法精度是很糟糕的,并且越靠近0越糟糕。比如输入0.015625,输出为0.246338,与0.25差了0.034左右,远远大于要求的0.001.

所以,在|x|小于1的时候这种算法是不可行的。而|x|到1之间,以0.001为跨度,步骤也不多,这个时候,还不如用穷举法,利用y=x^3的单增性,margin的顶点所对应的cube就是输出结果。

当然,其实还有更好的算法,比如牛顿—拉普森算法,这需要更高的数学知识。感兴趣的同学可以自己查阅资料,根据牛顿—拉普森算法写出更好的代码。这就作为思考题,和对分搜索法殊途同归,我就不再啰嗦了

算法题解01——对分搜索求立方根相关推荐

  1. LeetCode 力扣算法题解汇总,All in One

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: https://fuxuemingzhu.cn 关键词:LeetCode,力扣,算法,题解,汇总,解析 把自己刷过的所有题目做一个整理, ...

  2. 基于改进遗传退火算法的0-1背包问题设计与实现

    JISHOUUNIVERSITY 本科生毕业设计 题    目: 基于改进遗传退火算法的0-1背包问题设计与实现 作    者: 秦峰 学   号: 20144042001 所属学院: 信息科学与工程 ...

  3. [01背包] 背包问题求具体方案(01背包+求方案数+思维)

    文章目录 0. 前言 1. 01背包+求方案数+思维 0. 前言 相关: [背包] 背包问题算法模板(模板) 1. 01背包+求方案数+思维 12. 背包问题求具体方案 求方案数也是背包问题.dp 的 ...

  4. 东北大学第二场算法题解报告

    7-1 N个数求和 题解 按照小学学的分数,将输入的分数全部通分,然后分子分母求最大公约数化简 由题目知分数输入的时候均以 分子/分母 给出,我们可以利用 scanf 中的格式符进行输入 代码 #in ...

  5. 算法题解——将字符串转化为ip地址

    算法题解--将字符串转化为ip地址 题目描述 现在有一个只包含数字的字符串,将该字符串转化成IP地址的形式,返回所有可能的情况. 例如: 给出的字符串为"25525511135", ...

  6. 2的立方根用计算机怎样摁,立方根练习2doc用计算器求立方根.doc

    宝鸡市陇县堎底下中学"高效课堂"教学工具 七年级导学案 PAGE PAGE 2 把规范修炼成一种习惯,把认真内化成一种性格 平方根与立方根 导学案 设计 宋天恩审核 七年级数学学科 ...

  7. [01背包] 数字组合(01背包+求方案数)

    文章目录 0. 前言 1. 01背包求方案数 0. 前言 相关: [背包] 背包问题算法模板(模板) 1. 01背包求方案数 278. 数字组合 将 M 看作背包容量,每个数看成一个物品,Ai 看成是 ...

  8. 【学习笔记】使用魔数快速求立方根

    [学习笔记]使用魔数快速求立方根 简介 介绍使用魔数0x2a517d47快速求立方根 x 3 {\sqrt[3]{x}} 3x ​的C语言实现和公式的推导. 代码 float MagicCubeRoo ...

  9. 题库练习7(最小公倍数、求立方根、字符串逆序、记负均正、字符串分割)

    1. 求最小公倍数 import java.util.*;public class Main{public static void main(String[] args){Scanner sc=new ...

最新文章

  1. Corner Proposal Network 论文阅读(2020ECCV)
  2. 如何遍历JavaScript对象?
  3. UA PHYS515 电磁理论II 静电场问题3 边值问题及其解的唯一性
  4. BERT源码分析(PART II)
  5. python学习——把计算GC含量的代码封装成函数
  6. php试题与答案(二),php面试题附答案二
  7. 问题解决:Sublime 乱码显示GBK编码文件解决
  8. 技术人的危机-非理性的繁荣
  9. 如何在 Mac 上修改鼠标指针颜色?
  10. python画五角星_Python第25课:海龟绘图_自定义函数的应用
  11. Android API介绍
  12. SAP系统如何打NOTE?
  13. 华为系统固件服务器,华为手机固件
  14. speak 计算机英语作文,【必备】英语作文5篇
  15. 主机插耳机没声音问题
  16. 用计算机弹我们不一样谱子,我们不一样钢琴谱
  17. 身份证识别SDK——混合非原生调用
  18. 虎牙在全球 DNS 秒级生效上的实践
  19. 自动化测试+性能面试题整理--个人最新【持续更新】
  20. 黑科技网站第三弹 怀旧游戏集锦

热门文章

  1. 公积金单位账号和个人账号
  2. 笔记本重装系统如何找回之前自己自带的office
  3. 如何将卫星影像或者航拍影像叠加到CAD设计图上(Auto CAD版)
  4. 原型设计工具Axure RP9下载、中文语言操作说明(赠授权码)
  5. 基于FDE(有限元差分)算法模拟环形谐振器
  6. 如何修改第三方DLL文件名
  7. Java并发编程|第二篇:线程生命周期
  8. prometheus-community-PushProx介绍
  9. 吴恩达 深度学习 序列模型 第一周 编程作业二 字符级别语言模型项目 总结
  10. Windows BitLocker驱动器加密