精华内容
下载资源
问答
  • java程序中怎么调用平方根函数
    千次阅读
    2021-03-06 19:00:10

    展开全部

    在java.lang包中有个public final Math类,类中函数如下

    static double abs(double a)

    返回 double 值的绝对32313133353236313431303231363533e58685e5aeb931333264663766值。

    static float abs(float a)

    返回 float 值的绝对值。

    static int abs(int a)

    返回 int 值的绝对值。

    static long abs(long a)

    返回 long 值的绝对值。

    static double acos(double a)

    返回一个值的反余弦;返回的角度范围在 0.0 到 pi 之间。

    static double asin(double a)

    返回一个值的反正弦;返回的角度范围在 -pi/2 到 pi/2 之间。

    static double atan(double a)

    返回一个值的反正切;返回的角度范围在 -pi/2 到 pi/2 之间。

    static double atan2(double y, double x)

    将矩形坐标 (x, y) 转换成极坐标 (r, theta),返回所得角 theta。

    static double cbrt(double a)

    返回 double 值的立方根。

    static double ceil(double a)

    返回最小的(最接近负无穷大)double 值,该值大于等于参数,并等于某个整数。

    static double copySign(double magnitude, double sign)

    返回带有第二个浮点参数符号的第一个浮点参数。

    static float copySign(float magnitude, float sign)

    返回带有第二个浮点参数符号的第一个浮点参数。

    static double cos(double a)

    返回角的三角余弦。

    static double cosh(double x)

    返回 double 值的双曲线余弦。

    static double exp(double a)

    返回欧拉数 e 的 double 次幂的值。

    static double expm1(double x)

    返回 ex -1。

    static double floor(double a)

    返回最大的(最接近正无穷大)double 值,该值小于等于参数,并等于某个整数。

    static int getExponent(double d)

    返回 double 表示形式中使用的无偏指数。

    static int getExponent(float f)

    返回 float 表示形式中使用的无偏指数。

    static double hypot(double x, double y)

    返回 sqrt(x2 +y2),没有中间溢出或下溢。

    static double IEEEremainder(double f1, double f2)

    按照 IEEE 754 标准的规定,对两个参数进行余数运算。

    static double log(double a)

    返回 double 值的自然对数(底数是 e)。

    static double log10(double a)

    返回 double 值的底数为 10 的对数。

    static double log1p(double x)

    返回参数与 1 之和的自然对数。

    static double max(double a, double b)

    返回两个 double 值中较大的一个。

    static float max(float a, float b)

    返回两个 float 值中较大的一个。

    static int max(int a, int b)

    返回两个 int 值中较大的一个。

    static long max(long a, long b)

    返回两个 long 值中较大的一个。

    static double min(double a, double b)

    返回两个 double 值中较小的一个。

    static float min(float a, float b)

    返回两个 float 值中较小的一个。

    static int min(int a, int b)

    返回两个 int 值中较小的一个。

    static long min(long a, long b)

    返回两个 long 值中较小的一个。

    static double nextAfter(double start, double direction)

    返回第一个参数和第二个参数之间与第一个参数相邻的浮点数。

    static float nextAfter(float start, double direction)

    返回第一个参数和第二个参数之间与第一个参数相邻的浮点数。

    static double nextUp(double d)

    返回 d 和正无穷大之间与 d 相邻的浮点值。

    static float nextUp(float f)

    返回 f 和正无穷大之间与 f 相邻的浮点值。

    static double pow(double a, double b)

    返回第一个参数的第二个参数次幂的值。

    static double random()

    返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。

    static double rint(double a)

    返回最接近参数并等于某一整数的 double 值。

    static long round(double a)

    返回最接近参数的 long。

    static int round(float a)

    返回最接近参数的 int。

    static double scalb(double d, int scaleFactor)

    返回 d × 2scaleFactor,其舍入方式如同将一个正确舍入的浮点值乘以 double 值集合中的一个值。

    static float scalb(float f, int scaleFactor)

    返回 f × 2scaleFactor,其舍入方式如同将一个正确舍入的浮点值乘以 float 值集合中的一个值。

    static double signum(double d)

    返回参数的符号函数;如果参数为 0,则返回 0;如果参数大于 0,则返回 1.0;如果参数小于 0,则返回 -1.0。

    static float signum(float f)

    返回参数的符号函数;如果参数为 0,则返回 0;如果参数大于 0,则返回 1.0;如果参数小于 0,则返回 -1.0。

    static double sin(double a)

    返回角的三角正弦。

    static double sinh(double x)

    返回 double 值的双曲线正弦。

    static double sqrt(double a)

    返回正确舍入的 double 值的正平方根。

    static double tan(double a)

    返回角的三角正切。

    static double tanh(double x)

    返回 double 值的双曲线余弦。

    static double toDegrees(double angrad)

    将用弧度表示的角转换为近似相等的用角度表示的角。

    static double toRadians(double angdeg)

    将用角度表示的角转换为近似相等的用弧度表示的角。

    static double ulp(double d)

    返回参数的 ulp 大小。

    static float ulp(float f)

    返回参数的 ulp 大小。

    2Q==

    已赞过

    已踩过<

    你对这个回答的评价是?

    评论

    收起

    更多相关内容
  • 实现平方根函数sqrt

    千次阅读 2017-09-02 14:27:54
    本文将从一道经典的面试题说起:实现平方根函数,不得调用其他库函数。 函数原型声明如下: 1 double Sqrt(double A); 二分法 二分法的概念 求,等价于求方程的非...

    本文将从一道经典的面试题说起:实现平方根函数,不得调用其他库函数。

    函数原型声明如下:

    1 double Sqrt(double A);

    二分法

    二分法的概念

    ,等价于求方程的非负根(解)。求解方程近似根的方法中,最直观、最简单的方法是二分法。“二分法”算法步骤如下:

    1. 先找出一个区间 [a, b],使得f(a)与f(b)异号。
    2. 求该区间的中点 m = (a+b)/2,并求出 f(m) 的值。
    3. 若 f(m) * f(a) < 0 则取 [a, m] 为新的区间, 否则取 [m, b].
    4. 重复第2和第3步至理想精确度为止。

    二分法的过程可用下图表示:



    初始区间的选定

    可见,若要用“二分法”求方程,首先要找到一个区间 [a, b],使得f(a),f(b)异号。a可以取0,这很容易想到;但b如何选取,即如何选取b=f(A),使得

    取f(A)=A?不行,因为它不能始终保证



    从图像可知,当A>1时,才有。若用A作为第一步的上界,则在A小于1时,将无法得到正确结果。

    同时可知,sqrt(A)在原点处的切线平行于y轴,所以找不到常数项为零的多项式f(A),使得

    据此,可推出一个,使得成立。

    ,则t>=0,, 等价于,即

    显然,当时,上式成立,所以k可以取[1/4, +∞)的任意值,不妨取k=1/4,即有

    ,使得成立。

    二分法的误差

    为了说明二分法的误差,需要借助一个定理。
    零点定理:若f(x)在(a,b)连续,且f(a)f(b)<0,则f(0)在(a, b)内有零点。 
    二分法每次迭代都能够保证实际解在区间[a, b]范围内,所以每次迭代的误差都小于当前区间的宽度,这也是迭代的结束条件(通常误差给定)。


    二分法实现sqrt

    根据以上分析,可以很快写出sqrt的“二分法”版本:

    01 double Sqrt(double A)
    02 {
    03     double a = 0.0, b = A + 0.25, m; // b = A 是错误的上界
    04      
    05     // while(b - a > 2*DBL_EPSILON) { // sometimes dead cycle when m==a or m==b.
    06     for(;;) {
    07         m = (b + a)/2;
    08         if( m-a < DBL_EPSILON || b-m < DBL_EPSILON ) break;
    09         if( (m*m - A) * (a*a - A) < 0 ) b = m;
    10         else a = m;
    11     }
    12     return m;
    13 }

    需要注意的是:

    • 初始上界是A+0.25,而不是A;
    • double型的精度DBL_EPSILON,不能随意指定;


    牛顿迭代法

    下面介绍另一种应用广泛的方法——牛顿迭代法。

    牛顿法的概念

    牛顿迭代法是迭代法的一种,它的迭代格式为:

     

    牛顿法具有明显的几何意义,x[k+1]正是曲线在x[k]处的切线与x轴的交点的横坐标。因此,牛顿法也称切线法。

    来自Wikipedia的一个动态图很好的解释了这种几何意义:



    牛顿法初值的选定

    在开始牛顿迭代法之前,需要选定一个d迭代初值x0。根据前文分析,求sqrt(A),也可以取x0 = A+0.25;

    牛顿法sqrt

    根据牛顿法,求即求的非负根,
    所以,此时的牛顿递推式为:
     

    离实现牛顿法还差关键一步:迭代的结束条件。

    在不知道误差公式,且要求误差尽可能小情况下可以使用另一种方法——限定f(x)=0的误差(此法仅限于不给误差范围,且要求误差尽可能小时使用)。


    据此,实现的sqrt如下:

    01 double Sqrt(double A)
    02 {
    03     double x0 = A + 0.25, x1, xx = x0;
    04     for(;;) {
    05         x1 = (x0*x0 + A) / (2*x0);
    06         if(fabs(x1 - x0) <= DBL_EPSILON) break;
    07         if(xx == x1) break// to break two value cycle.
    08         xx = x0;
    09         x0 = x1;
    10     }
    11  
    12     return x1;
    13 }

    这段程序里的while条件是fabs(x1*x1-A) > 5*DBL_EPSILON是因为,x的误差在2*DBL_EPSILON范围内,所以x*x的误差就在4*DBL_EPSILON范围,考虑到浮点乘法的精度丢失,所以为5*DBL_EPSILON。

    迭代法的理论基础

    迭代格式收敛的前提

    迭代法在进行“迭代”之前,需将原方程改写成的形式;再用迭代格式,逐次逼近的实际解x*。

    整个过程的所有x构成了数列:(迭代序列),数列的递推式即

    所以,迭代法能够求得近似解的前提是

             

    其中x*为方程的实际解。


    迭代格式收敛的条件

    迭代法收敛的前提是 ,这很好理解;但要用此式验证迭代式是否收敛,必须先通过递推式求出通项

    是否有更简单的方法判定迭代格式收敛?当然有,下面介绍一个定理能够简便的判定迭代格式是否收敛,同时也能判定误差。




    定理  迭代格式收敛条件(Vipschitz条件)

    若迭代函数满足:

    ①一阶导数连续;

    ②当x∈[a, b]时,有

    ③存在常数,使得

    1. 方程有唯一根x*;
    2. 对任意x0∈[a, b],迭代格式收敛,且
    3. ,(事后误差估计);
    4. ,(事前误差估计);



    定理应用

    下面以求的近似解为例,说明定理如何用:


    1)判断收敛

    对应的迭代函数为:


    它的导函数为:


    在[0, A+0.25]区间内它显然连续,且存在L=1/2使得;即满足收敛的三个条件;


    2)估计误差(迭代次数)

    有了L = 1/2;就可以根据定理估算:

    ①给定误差情况下,需要迭代几次?

    ②给定迭代次数,最终近似解的误差?

    比如,假设题目要求的精度是:小数点后2位(精确到0.01),那么误差要小于0.01 / 2 = 0.005;只需根据初值x0和第一次迭代结果x1和定理的结论4,便可算出迭代次数k,这里不再罗列(公式编辑起来比较麻烦)。

    同样,根据x0,x1和结论4,也可以很方便的算出第k次迭代的误差;


    推广——一般方程求近似解

    本文指出的二分法、牛顿迭代法是求解方程近似解的常见方法,不仅仅限于求sqrt,但在本文所实现的sqrt程序的基础上,可以很快实现求解其他方程的程序。

    二分法

    比如,如下程序段就是二分法求解任意方程f(x)=0的程序:

    01 double bisection(double (*f)(double), double a, double b, double eps)
    02 {
    03     double m;
    04     assert( f != NULL && f(a) * f(b) < 0.0 && (b-a) > DBL_EPSILON); // (b-a) > DBL_EPSILON 即 b > a
    05  
    06     while( b - a > eps ) {
    07         m = (a + b)/2;
    08         if( f(m) * f(a) < 0.0 ) b = m;
    09         else a = m;
    10     }
    11     return m;
    12 }

    这个程序较为“好用”,只需给出函数f,区间[a, b],误差eps即可。


    迭代法

    同样,有了对迭代法的理论基础,我们知道了迭代法的误差如何估计。下面是迭代法求一般方程的近似解的程序:

    01 double iteration(double (*g)(double), double L, double x0, double eps)
    02 {
    03     double x1, t = L/(1 - L);;
    04     for(;;) {
    05         x1 = g(x0);
    06         if(fabs( t*(x1-x0) ) < eps)
    07             break;
    08         x0 = x1;
    09     }
    10     return x1;
    11 }

    这个函数没有上面的二分法那么好用,因为需要根据f(x)自行推出递推函数g,并根据递推函数的倒数找到一个常数L;再给出初值x0,误差eps。


    割线法

    事实上,真正通用的牛顿法很难实现,因为从f(x)推出它的导函数f1(x)的过程并不容易。割线法可以避免这一难题,它使用差商:


    来代替牛顿公式中的导数f'(xk),于是得到了“割线法”迭代公式:


    割线法和牛顿法类似,有着明确的几何意义。下面的gif动态地展示了割线法的几何意义(若没有看到动画效果可尝试刷新本页):


    (图片来自Dr. Mathews的教案,)

    割线法求一般方程的近似解的程序如下:

    01 double secant(double (*f)(double), double x0, double x1, double eps)
    02 {
    03     double x2;
    04     for(;;) {
    05         x2 = x1 - f(x1)/(f(x1) - f(x0))*(x1 - x0);
    06         iffabs(x2-x1) < eps )
    07             break;
    08         x0 = x1;
    09         x1 = x2;
    10     }
    11     return x2;
    12 }

    这个函数也很好使用,只需给出f,[a, b],eps即可。

    割线法实现的sqrt如下:

    01 double Sqrt(double A)
    02 {
    03     double x0 = 0, x1 = A+0.25, x2;
    04     double fx0 = x0*x0 - A, fx1 = x1*x1 - A;
    05      
    06     for(;;) {
    07         x2 = x1 - fx1*(x1-x0) / (fx1-fx0);
    08         if(fabs(x2 - x1) < 2*DBL_EPSILON)
    09             break;
    10         x0 = x1; fx0 = fx1;
    11         x1 = x2; fx1 = x2*x2 - A;
    12     }
    13     return x2;
    14 }


    收敛速度对比

    对于sqrt的实现,本文介绍了三种方法,分别为:二分法,牛顿法,割线法;

    二分法的收敛速度

    对于二分法,相邻两次的误差ek+1和ek间的关系为:

    由此,我们可以引申出迭代法收敛速度的判定标准:


    定义  迭代法收敛的阶

    设序列{xk}收敛于x*,并记ek = xk - x*,如果存在非负常数c和正常数p,使得


    则称序列{xk}是p阶收敛的。当p=1,且0<|c|<1时,称为线性收敛;当p>1时,称超线性收敛,特别是p=2时,称平方收敛


    由收敛阶的定义可知,二分法是线性收敛的。

    牛顿法的收敛速度

    要确定牛顿法收敛的阶,需要经过一番推导,限于篇幅,这里直接给出结论:

    当x*是f(x)=0的单根(回顾一下二次方程)时,牛顿法至少是二阶收敛的;

    当x*是f(x)=0的重根时,牛顿法至少是一阶收敛的。

    割线法的收敛速度

    分析割线法收敛的阶同样不易,它比牛顿法略慢一些;有知道的同学可以告诉我;

    实验对比

    下面通过实验对比几种方法的收敛速度。实验以不同版本的sqrt求出最终值所用的迭代次数为收敛速度的标准。
    实验程序如下:
    01 #include <math.h> // for fabs sqrt
    02 #include <float.h> // for DBL_EPSILON DBL_DIG etc.
    03 #include <time.h> // for clock
    04 #include <stdio.h>
    05 #include <assert.h>
    06  
    07 int iterateCount = 0;
    08 double BisectionSqrt(double A)
    09 {
    10     double a = 0.0, b = A + 0.25, m;
    11      
    12     for(;;){
    13         m = (b + a)/2;
    14         ++iterateCount; // count iterate.
    15         // printf("  %.15f\n", m);
    16         if( m-a < DBL_EPSILON || b-m < DBL_EPSILON ) break;
    17         if( (m*m - A) * (a*a - A) < 0.0 ) b = m;
    18         else a = m;
    19     }
    20     return m;
    21 }
    22  
    23 double NewtonSqrt(double A)
    24 {
    25     double x0 = A + 0.25, x1, xx;
    26     for(;;) {
    27         x1 = (x0*x0 + A) / (2*x0);
    28         ++iterateCount; // count iterate.
    29         // printf("  %.15f\n", m);
    30         if(fabs(x1 - x0) <= DBL_EPSILON) break;
    31         if(xx == x1) return x0; // break two value cycle.
    32         xx = x0;
    33         x0 = x1;
    34     }
    35  
    36     return x1;
    37 }
    38  
    39 double SecantSqrt(double A)
    40 {
    41     double x0 = 0, x1 = A+0.25, x2;
    42     double fx0 = x0*x0 - A, fx1 = x1*x1 - A;
    43      
    44     for(;;) {
    45         x2 = x1 - fx1*(x1-x0) / (fx1-fx0);
    46         ++iterateCount; // count iterate.
    47         // printf("  %.15f\n", x2);
    48         if(fabs(x2 - x1) < 2*DBL_EPSILON)
    49             break;
    50         x0 = x1; fx0 = fx1;
    51         x1 = x2; fx1 = x2*x2 - A;
    52     }
    53     return x2;
    54 }
    55  
    56 int main()
    57 {
    58 #ifdef F_INFO
    59     puts("local machine floating point informations:");
    60     printf("FLT_DIG: %d, %g\n", FLT_DIG, FLT_EPSILON);
    61     printf("LDBL_DIG: %d, %g\n", DBL_DIG, DBL_EPSILON);
    62     printf("LDBL_DIG: %d, %g\n", LDBL_DIG, LDBL_EPSILON);
    63 #endif
    64  
    65     double x, res, stdres;
    66      
    67     whilescanf("%lf", &x) == 1 )
    68     {
    69         stdres = sqrt(x);
    70         printf("%15g ", x);
    71          
    72         iterateCount = 0;
    73         res = BisectionSqrt(x);
    74         printf("%14g\t%3d\t", res-stdres, iterateCount);
    75          
    76         iterateCount = 0;
    77         res = NewtonSqrt(x);
    78         printf("%14g\t%3d\t", res-stdres, iterateCount);
    79          
    80         iterateCount = 0;
    81         res = SecantSqrt(x);
    82         printf("%14g\t%3d\t", res-stdres, iterateCount);
    83          
    84         printf("\n");
    85     }
    86      
    87     return 0;
    88 }
    程序输出\t是为了方便重定位到文本文件后,粘贴到excel等表格软件中;格式串是为了方便控制台查看;

    测试数据由下面的python脚本生成:
    01 for in range(110000):
    02     print x*0.01
    03      
    04 for in range(1000090000):
    05     print x
    06      
    07 for in range(1000000900000037):
    08     print x
    09  
    10 for in range(100000000100000000002311):
    11     print x

    可以通过管道进行测试: