一 序
本篇属于算法整理系列。
不能否认,有的大公司重视基础,算法可能就是重要考察点。
题目:实现函数:
double
sqrt
(
int
v,
double
t)
假设函数的返回结果为 r
, 要求 r 要满足一定的误差条件, 用公式表达就是:
, 其中 开根号V是真实的值 , t 为给定的一个误差, 例如0.1 。
二 循环法
如果面试时候,面试官问你这个问题,加上一个限制:不能使用math.sqrt.
其实脑子第一反应就是脑子有病,为啥不用,实际工作中也没这样的需求啊,我用计算器也能算。但是还是得冷静下来。
想想面试官是为了考察啥。
要是卡住或者说不会就太尴尬了。
简单的思路就是让程序模拟大脑计算。比如我们习惯性的记住整数的,比如4的是开根号是2,9的开根号是3,很少有人去专门记忆2的是1.414.。。
所以
先用一个循环找到 r, 使得 r^2 是离给定 v 最近的平方数。用精度小的去作为step.
没循环一次,就累加一下步长。
其实是能算出来的,也能满足精度需求,就是不是最优解。因为毕竟暴力循环耗时长一些。
有个矛盾:要想精度高,步长就要小,步长小了,循环次数就多,所以有个均衡考虑。
推广思考下:如果有个业务场景,不断尝试推送消息给用户,用户不在线就收不到,消息的数量有很多。
所以你要每秒去推送,可能推送不过来。所以对于重试推送的,可以适当的调大时间间隔step.
30秒再试。30分钟再试,3小时再试。等等,几次都失败就废弃,认为不可达。
三 二分查找法:
二分搜索或者折半查找很多人在大学是学过的,数据结构就涉及这块。
当然注意一下边界条件,就不展开了,可以看下demo
当然能做到这一步,基本上面试就算过了。
四 牛顿迭代法
我是不懂的,数学学得一塌糊涂。从百科上给自己科普一下:https://baike.baidu.com/item/%E7%89%9B%E9%A1%BF%E8%BF%AD%E4%BB%A3%E6%B3%95
设r是
的根,选取
作为r的初始近似值,过点
做曲线
的切线L,L的方程为
,求出L与x轴交点的横坐标
,称x
1
为r的一次近似值。过点
做曲线
的切线,并求该切线与x轴交点的横坐标
,称
为r的二次近似值。重复以上过程,得r的近似值序列,其中,
称为r的
次近似值,上式称为
牛顿迭代公式
。
直接对应的开根号公式:
demo:
package com.daojia.math;
public class SquereTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
long t1 =System.currentTimeMillis();
double srt = Math.sqrt(100000000.0);
System.out.println("jdkuse:"+(System.currentTimeMillis()-t1)+":"+srt);
double jingdu = 0.001;
long t2 =System.currentTimeMillis();
double srt1 = sq1(100000000.0,0.001);
System.out.println("循环use:"+(System.currentTimeMillis()-t2)+":"+srt1);
System.out.println(Math.abs(srt1-srt)=1?num:1);
mid=(low+up)/2;
do{
if(mid*mid>num)
{
up = mid;
}else{
low = mid;
}
last=mid;
mid=(up+low)/2;
}while(Math.abs(mid-last)>jingdu);
return mid;
}
/*
* 牛顿迭代法
*
*/
public static double sq3(double num,double jingdu){
if(num<0)
{
return -1;
}
double x=num,y=0.0;
while(Math.abs(x-y)>0.00001){
y=x;
x=0.5*(x+num/x);
}
return x;
}
}
jdkuse:0:10000.0
2.0E-4
循环use:147:10000.000011057207
true
二分法use:0:9999.999747378752
true
牛顿法use:0:10000.0
true
我们可以看出,现在计算机还是很快的,对于1亿,精度要求0.001的情况下。用了147毫秒。
二分法时间个jdk的math一样。但是结果不如牛顿迭代法的高。
因为jdk的math是直接调用了public static native double sqrt(double a);
这个native的方法时比Java更快的C语言编写的。我们不可见源码。但是从效果对比来看,牛顿迭代法显然是最优的选择。
************************************************************
还是懂数学的好,
底层还是博大精深。有太多的东西需要学习。