你不知道的sqrt函数

来源:互联网 发布:最新ppt软件下载 编辑:程序博客网 时间:2024/05/13 04:35

     进来的朋友我相信你们被我的标题所吸引了,好吧!我承认我确实有点标题党了,我所要介绍的我们常用的sqrt函数用法可能大家都已经了解,只有博主我还在探索中。

     大家都经常用到一些常用的计算函数,你如sqrt,abs,exp等等,今天我就以sqrt来说,系统是怎么来实现调用sqrt这个函数的。

     我们都知道有一种方法计算开平方根,比如根号16,我们会有这样一种办法,首先找出16的一半,即(0+16)/2=8;然后我们发现8*8=64>>16;所以我们继续寻找8的一般的数,最后找到4,发现4*4=16;然后我们就求出16的开平方根等于4。这种方法即为我们学过的数据结构中的二分查找法。下面是我myeclipse测试代码以及生成的结果。

    代码如下:

                   package com.practice;
import java.util.*;

public class Test {    
    public static void main(String[] args) {
        double a=569.9999;
        long startTime=System.nanoTime();   //获取开始时间
        double result=SqrtDichotomy(a);
        long endTime=System.nanoTime();
        System.out.println("采用二分法计算结果为:"+result);
        System.out.println("二分法执行时间为:"+(endTime-startTime)+"ns");
        long startSystemTime=System.nanoTime();
        double systemResult=Math.sqrt(a);
        long endSystemTime=System.nanoTime();
        System.out.println("系统计算结果为:"+systemResult);
        System.out.println("系统执行时间为:"+(startSystemTime-endSystemTime)+"ns");
        
        
    }

     //采用二分法
    public static double SqrtDichotomy (double n)
    {
        if(n<0)
            return n;
        double mid,last;
        double low,up;
        low=0;
        up=n;
        mid=(low+up)/2;
        do
        {
            if(mid*mid>n)
                up=mid;
            else
                low=mid;
            last=mid;
            mid=(up+low)/2;
        }while(Math.abs(mid-last) > 1e-308);//精度控制
        return mid;
    }



}


         

     

从执行结果看出,系统执行效率是二分法的不知道多少倍了,性能差的没法比,要是中国发射卫星这样的话,火箭不爆炸才怪。那是什么原因导致差别这么大勒,二分查找已经很好了,我记得数据结构老师还特地讲了二分法,难道还有什么更加高效率的方式。

      偶然在网上发现一种算法:牛顿迭代法快速寻找平方根,或者这种方法可以帮助我们,具体步骤如下:

     求出根号a的近似值:首先随便猜一个近似值x,然后不断令x等于x和a/x的平均数,迭代个六七次后x的值就已经相当精确了。
例如,我想求根号2等于多少。假如我猜测的结果为4,虽然错的离谱,但你可以看到使用牛顿迭代法后这个值很快就趋近于根号2了:
(4 + 2/4) / 2 = 2.25
(2.25 + 2/2.25) / 2 = 1.56944..
(1.56944.. + 2/1.56944..) / 2 = 1.42189..
(1.42189.. + 2/1.42189..) / 2 = 1.41423..
....
这种算法的原理很简单,我们仅仅是不断用(x,f(x))的切线来逼近方程x^2-a=0的根。根号a实际上就是x^2-a=0的一个正实根,这个函数的导数是2x。也就是说,函数上任一点(x,f(x))处的切线斜率是2x。那么,x-f(x)/(2x)就是一个比x更接近的近似值。代入 f(x)=x^2-a得到x-(x^2-a)/(2x),也就是(x+a/x)/2。

     牛顿迭代法代码以及性能测试如下:

      package com.practice;
import java.util.*;

public class Test {    
    public static void main(String[] args) {
        double a=569.9999;
        long startTime=System.nanoTime();   //获取开始时间
        double result=SqrtDichotomy(a);
        long endTime=System.nanoTime();
        System.out.println("采用二分法计算结果为:"+result);
        System.out.println("二分法执行时间为:"+(endTime-startTime)+"ns");
          
        long startNewTonTime=System.nanoTime();   //获取开始时间
        double resultNewTon=SqrtNewTon(a);
        long endNewTonTime=System.nanoTime();
        System.out.println("采用牛顿迭代法计算结果为:"+result);
        System.out.println("牛顿迭代法执行时间为:"+(startNewTonTime-endNewTonTime)+"ns");
        
        
        long startSystemTime=System.nanoTime();
        double systemResult=Math.sqrt(a);
        long endSystemTime=System.nanoTime();
        System.out.println("系统计算结果为:"+systemResult);
        System.out.println("系统执行时间为:"+(startSystemTime-endSystemTime)+"ns");
        
        
    }


    public static double SqrtNewTon(Double x)//
    {
        double val = x; //最终
        double last; //保存上一个计算的值
        do
        {
            last = val;
            val =(val + x/val) / 2;
        }while(Math.abs(val-last) > 1e-308);
        return val;
    }


    
     //采用二分法
    public static double SqrtDichotomy (double n)
    {
        if(n<0)
            return n;
        double mid,last;
        double low,up;
        low=0;
        up=n;
        mid=(low+up)/2;
        do
        {
            if(mid*mid>n)
                up=mid;
            else
                low=mid;
            last=mid;
            mid=(up+low)/2;
        }while(Math.abs(mid-last) > 1e-308);//精度控制
        return mid;
    }
 

}

         性能: 


是不是感觉快了许多,但是和我们的系统执行结果相比,还是逊色饿许多;

难道还有什么神奇的算法我不知道,我只能写到这里了,待我查明资料再来继续完成,我相信一定有什么算法接近系统效率或则超过系统。

以上结果为纳秒级别!!!!

      



    

原创粉丝点击