java.lang.math(java lang math)
一、java.lang是什么意思
lang是 language(语言)的简写
是java中常用方法最多的包
包含常用类软件包 java.lang的描述提供利用 Java编程语言进行程序设计的基础类。最重要的类是 Object(它是类层次结构的根)和 Class(它的实例表示正在运行的应用程序中的类)。
把基本类型的值当成一个对象来表示通常很有必要。包装器类 Boolean、Character、Integer、Long、Float和 Double就是用于这个目的。例如,一个 Double类型的对象包含了一个类型为 double的字段,这表示如果引用某个值,则可以将该值存储在引用类型的变量中。这些类还提供了大量用于转换基值的方法,并支持一些标准方法,比如 equals和 hashCode。Void类是一个非实例化的类,它保持一个对表示基本类型 void的 Class对象的引用。
类 Math提供了常用的数学函数,比如正弦、余弦和平方根。类似地,类 String和 StringBuffer提供了常用的字符串操作。
类 ClassLoader、Process、Runtime、SecurityManager和 System提供了管理类的动态加载、外部进程创建、主机环境查询(比如时间)和安全策略实施等“系统操作”。
类 Throwable包含了可能由 throw语句抛出的对象(§14.16)。Throwable的子类表示错误和异常。
包规范
字符编码
java.nio.charset.Charset类的规范描述了字符编码的命名约定,以及每个 Java平台实现必须支持的标准编码集。
二、Java Math类中的新功能,第1 部分:实数
摘要在这篇由两部分组成的文章中 Elliotte Rusty Harold与您一起探讨经典 java lang Math类中的新功能第部分主要讨论比较单调的数学函数第部分将探讨专为操作浮点数而设计的函数
有时候您会对一个类熟悉到忘记了它的存在如果您能够写出 java lang Foo的文档那么 Eclipse将帮助您自动完成所需的函数您无需阅读它的 Javadoc例如我使用 java lang Math(一个我自认为非常了解的类)时就是这样但令我吃惊的是我最近偶然读到它的 Javadoc——这可能是我近五年来第一次读到我发现这个类的大小几乎翻了一倍包含种我从来没听说过的新方法看来我要对它另眼相看了
Java&#;语言规范第版向 java lang Math(以及它的姊妹版 java lang StrictMath)添加了种新方法 Java又添加了种在本文中我重点讨论其中的比较单调的数学函数如 log和 cosh在第部分我将探讨专为操作浮点数(与抽象实数相反)而设计的函数
抽象实数(如π或)与 Java double之间的区别很明显首先数的理想状态是具有无限的精度而 Java表示法把数限制为固定位数在处理非常大和非常小的数时这点很重要例如(二十亿零一)可以精确表示为一个 int而不是一个 float最接近的浮点数表示形式是 E—即两亿使用 double数会更好因为它们的位数更多(这是应该总是使用 double数而不是 float数的理由之一)但它们的精度仍然受到一定限制
计算机算法(Java语言和其他语言的算法)的第二个限制是它基于二进制而不是十进制/和/之类的分数可用十进制精确表示(分别是和)但用二进制表示时就会出现重复的分数如同/在用十进制表示时就会变为……以为基数任何分母仅包含质数因子和的分数都可以精确表示以为基数则只有分母是的乘方的分数才可以精确表示////等
这种不精确性是迫切需要一个 math类的最主要的原因之一当然您可以只使用标准的+和*运算符以及一个简单的循环来定义三角函数和其他使用泰勒级数展开式的函数如清单所示
清单使用泰勒级数计算正弦
public class SineTaylor{ public static void main(String[] args){ for(double angle=; angle<=*Math PI; angle+= Math PI/){ System out println(degrees(angle)+ \t+ taylorSeriesSine(angle)+ \t+ Math sin(angle));}} public static double degrees(double radians){ return* radians/ Math PI;} public static double taylorSeriesSine(double radians){ double sine=; int sign=; for(int i=; i<; i+=){ sine+= Math pow(radians i)* sign/ factorial(i); sign*=;} return sine;} private static double factorial(int i){ double result=; for(int j=; j<= i; j++){ result*= j;} return result;}}
开始运行得不错只有一点小的误差如果存在误差的话也只是最后一位小数不同
但是随着角度的增加误差开始变大这种简单的方法就不是很适用了
这里使用泰勒级数得到的结果实际上比我想像的要精确但是随着角度增加到度度( pi弧度)以及更大时泰勒级数就逐渐需要更多条件来进行准确计算 java lang Math使用的更加完善的算法就避免了这一点
泰勒级数的效率也无法与现代桌面芯片的内置正弦函数相比要准确快速地计算正弦函数和其他函数需要非常仔细的算法专门用于避免无意地将小的误差变成大的错误这些算法一般内置在硬件中以更快地执行例如几乎每个在最近年内组装的 X芯片都具有正弦和余弦函的硬件实现 X VM只需调用即可不用基于较原始的运算缓慢地计算它们 HotSpot利用这些指令显著加速了三角函数的运算
直角三角形和欧几里德范数
每个高中学生都学过勾股定理在直角三角形中斜边边长的平方等于两条直角边边长平方之和即 c= a+ b
学习过大学物理和高等数学的同学会发现这个等式会在很多地方出现不只是在直角三角形中例如 R的平方二维向量的长度三角不等式等都存在勾股定理(事实上这些只是看待同一件事情的不同方式重点在于勾股定理比看上去要重要得多)
Java添加了 Math hypot函数来精确执行这种计算这也是库很有用的一个出色的实例证明原始的简单方法如下
public static double hypot(double x double y){ return x*x+ y*y;}
实际代码更复杂一些如清单所示首先应注意的一点是这是以本机 C代码编写的以使性能最大化要注意的第二点是它尽力使本计算中出现的错误最少事实上应根据 x和 y的相对大小选择不同的算法
清单实现 Math hypot
的实际代码/**====================================================* Copyright(C) by Sun Microsystems Inc All rights reserved** Developed at SunSoft a Sun Microsystems Inc business* Permission to use copy modify and distribute this* sofare is freely granted provided that this notice* is preserved*====================================================*/#include fdlibm h#ifdef __STDC__ double __ieee _hypot(double x double y)#else double __ieee _hypot(x y) double x y;#endif{ double a=x b=y t t y y w; int j k ha hb; ha= __HI(x)& x fffffff;/* high word of x*/ hb= __HI(y)& x fffffff;/* high word of y*/ if(hb> ha){a=y;b=x;j=ha; ha=hb;hb=j;} else{a=x;b=y;} __HI(a)= ha;/* a<|a|*/ __HI(b)= hb;/* b<|b|*/ if((ha hb)> x c){return a+b;}/* x/y>***/ k=; if(ha> x f){/* a>***/ if(ha>= x ff){/* Inf or NaN*/ w= a+b;/* for sNaN*/ if(((ha& xfffff)|__LO(a))==) w= a; if(((hb^ x ff)|__LO(b))==) w= b; return w;}/* scale a and b by***/ ha= x; hb= x; k+=; __HI(a)= ha; __HI(b)= hb;} if(hb< x b){/* b<***/ if(hb<= x fffff){/* subnormal b or*/ if((hb|(__LO(b)))==) return a; t=; __HI(t)= x fd;/* t= ^*/ b*= t; a*= t; k=;} else{/* scale a and b by ^*/ ha+= x;/* a*= ^*/ hb+= x;/* b*= ^*/ k=; __HI(a)= ha; __HI(b)= hb;}}/* medium size a and b*/ w= a b; if(w>b){ t=; __HI(t)= ha; t= a t; w= sqrt(t*t(b*( b) t*(a+t)));} else{ a= a+a; y=; __HI(y)= hb; y= b y; t=; __HI(t)= ha+ x; t= a t; w= sqrt(t*y(w*( w)(t*y+t*b)));} if(k!=){ t=; __HI(t)+=(k<<); return t*w;} else return w;}
实际上是使用这种特定函数还是几个其他类似函数中的一个取决于平台上的 JVM细节不过这种代码很有可能在 Sun的标准 JDK中调用(其他 JDK实现可以在必要时改进它)
这段代码(以及 Sun Java开发库中的大多数其他本机数学代码)来自 Sun约年前编写的开源 fdlibm库该库用于精确实现 IEE浮点数能进行非常准确的计算不过会牺牲一些性能
以为底的对数
对数说明一个底数的几次幂等于一个给定的值也就是说它是 Math pow()函数的反函数以为底的对数一般出现在工程应用程序中以 e为底的对数(自然对数)出现在复合计算以及大量科学和数学应用程序中以为底的对数一般出现在算法分析中
从 Java开始 Math类有了一个自然对数也就是给定一个参数 x该自然对数返回 e的几次幂等于给定的值 x遗憾的是 Java语言的(以及 C Fortran和 Basic的)自然对数函数错误命名为 log()在我读的每本数学教材中 log都是以为底的对数而 ln是以 e为底的对数 lg是以为底的对数现在已经来不及修复这个问题了不过 Java添加了一个 log()函数它是以为底而不是以 e为底的对数
清单是一个简单程序它输出整数到的以和 e为底的对数
清单到的各种底数的对数
public static void main(String[] args){ for(int i=; i<=; i++){ System out println(i+ \t+ Math log(i)+ \t+ Math log(i)+ \t+ lg(i));}}
public static double lg(double x){ return Math log(x)/Math log();}}
下面是前行结果
Math log()能正常终止对数函数执行或任何负数的对数返回 NaN
立方根
我不敢说我的生活中曾经需要过立方根我也不是每天都要使用代数和几何的少数人士之一更别提偶然涉足微积分微分方程甚至抽象代数因此下面这个函数对我毫无用处尽管如此如果意外需要计算立方根现在就可以了—使用自 Java开始引入的 Math cbrt()方法清单通过计算到之间的整数的立方根进行了演示
清单到的立方根
public class CubeRoots{ public static void main(String[] args){ for(int i=; i<=; i++){ System out println(Math cbrt(i));}}}
下面是结果
结果显示与平方根相比立方根拥有一个不错的特性每个实数只有一个实立方根这个函数只在其参数为 NaN时才返回 NaN
双曲三角函数
双曲三角函数就是对曲线应用三角函数也就是说想象将这些点放在笛卡尔平面上来得到 t的所有可能值
x= r cos(t)y= r sin(t)
您会得到以 r为半径的曲线相反假设改用双曲正弦和双曲余弦如下所示
x= r cosh(t)y= r sinh(t)
则会得到一个正交双曲线原点与它最接近的点之间的距离是 r
还可以这样思考其中 sin(x)可以写成(ei x e i x)/ cos(x)可以写成(ei x+ e i x)/从这些公式中删除虚数单位后即可得到双曲正弦和双曲余弦即 sinh(x)=(e x e x)/ cosh(x)=(e x+ e x)/
Java添加了所有这三个函数 sh() Math sinh()和 Math tanh()还没有包含反双曲三角函数—反双曲余弦反双曲正弦和反双曲正切
实际上 cosh(z)的结果相当于一根吊绳两端相连后得到的形状即悬链线清单是一个简单的程序它使用 sh函数绘制一条悬链线
清单使用 sh()绘制悬链线
import java awt*;
public class Catenary extends Frame{
private static final int WIDTH=; private static final int HEIGHT=; private static final double MIN_X=; private static final double MAX_X=; private static final double MAX_Y=;
private Polygon catenary= new Polygon();
public Catenary(String title){ super(title); setSize(WIDTH HEIGHT); for(double x= MIN_X; x<= MAX_X; x+=){ double y= sh(x); int scaledX=(int)(x* WIDTH/(MAX_X MIN_X)+ WIDTH/); int scaledY=(int)(y* HEIGHT/MAX_Y);// in puter graphics y extends down rather than up as in// Caretesian coordinates so we have to flip scaledY= HEIGHT scaledY; catenary addPoint(scaledX scaledY);}}
public static void main(String[] args){ Frame f= new Catenary( Catenary); f setVisible(true);}
public void paint(Graphics g){ g drawPolygon(catenary);}
}
图为绘制的曲线
图笛卡尔平面中的一条悬链曲线
双曲正弦双曲余弦和双曲正切函数也会以常见或特殊形式出现在各种计算中
符号
Math signum函数将正数转换为将负数转换为仍然是实际上它只是提取一个数的符号在实现 Comparable接口时这很有用
一个 float和一个 double版本可用来维护这种类型这个函数的用途很明显即处理浮点运算 NaN以及正和负的特殊情况 NaN也被当作正和负应该返回正和负例如假设如清单那样用简单的原始方法实现这个函数
清单存在问题的 Math signum实现
public static double signum(double x){ if(x==) return; else if(x<) return; else return;}
首先这个方法会将所有负转换为正(负可能不好理解但它确实是 IEEE规范的必要组成部分)其次它会认为 NaN是正的实际实现如清单所示它更加复杂而且会仔细处理这些特殊情况
清单实际的正确的 Math signum实现
public static double signum(double d){ return(d==|| isNaN(d))?d:copySign( d);}
public static double copySign(double magnitude double sign){ return rawCopySign(magnitude(isNaN(sign)? d:sign));}
public static double rawCopySign(double magnitude double sign){ return Double longBitsToDouble((Double doubleToRawLongBits(sign)&(DoubleConsts SIGN_BIT_MASK))|(Double doubleToRawLongBits(magnitude)&(DoubleConsts EXP_BIT_MASK| DoubleConsts SIGNIF_BIT_MASK)));}
事半功倍
最有效的代码是从您未编写过的代码不要做专家们已经做过的事情使用 java lang Math函数(新的和旧的)的代码将更快更有效而且比您自己编写的任何代码都准确所以请使用这些函数
三、Java中的Math函数
Math类:
java.lang.Math类中包含基本的数字操作,如指数、对数、平方根和三角函数。
java.math是一个包,提供用于执行任意精度整数(BigInteger)算法和任意精度小数(BigDecimal)算法的类。
java.lang.Math类中包含E和PI两个静态常量,以及进行科学计算的类(static)方法,可以直接通过类名调用。
public static final Double E= 2.7182818284590452354
public static final Double PI= 3.14159265358979323846
public static long abs(double x):传回 x的绝对值。X也可int long float
public static long sin(double x):传回x径度的正弦函数值
public static long cos(double x):传回x径度的余弦函数值
public static long tan(double x):传回x径度的正切函数值
public static long asin(double x):传回x值的反正弦函数值。
public static long acos(double x):传回x值的反余弦函数值。
public static long atan(double x):传回x值的反正切函数值。
public static long atan2(double x, double y):传回极坐标(polar)的θ值
public static long floor(double x):传回不大于x的最大整数值
public static long ceil(double x):传回不小于x的最小整数值。
public static long exp(double x):传回相当于ex值
public static long log(double x):传回x的自然对数函数值
public static long max(double x,double y):传回x、y较大数
public static long min(double x,double y):传回x、y较小数
public static long pow(double x,double y):传回x的y次幂值
public static long sqrt(double x):传回x开平方值
public static long rint(double x):传回最接近x的整数值
public static long round(double x):传回x的四舍五入值
public static long toDegrees(double angrad):传回将angrad径度转换成角度
public static long toRadians(double angdeg):传回将angdeg角度转换成径度
public static long random():传回随机数值,产生一个0-1之间的随机数(不包括0和1)
Math.log(100)/Math.log(10);
表示的是100的以10为底的对数函数的值,是2向上取整用Math.ceil(double a)向下取整用Math.floor(double a)。