目录
[1. Math.E](#1. Math.E)
[2. Math.PI](#2. Math.PI)
[1.绝对值计算:abs 系列方法](#1.绝对值计算:abs 系列方法)
[1. 加法:addExact](#1. 加法:addExact)
[2. 减法:subtractExact](#2. 减法:subtractExact)
[3. 乘法](#3. 乘法)
[1. ceil(double a):向上取整](#1. ceil(double a):向上取整)
[2. floor(double a):向下取整](#2. floor(double a):向下取整)
[3. rint(double a):四舍五入到最近整数(返回 double)](#3. rint(double a):四舍五入到最近整数(返回 double))
[4. round:四舍五入到整数(返回 int 或 long)](#4. round:四舍五入到整数(返回 int 或 long))
[1.1. exp(double a):计算自然指数 e^a](#1.1. exp(double a):计算自然指数 e^a)
[1.2. expm1(double x):计算 e^x - 1](#1.2. expm1(double x):计算 e^x - 1)
[1.3. pow(double a, double b):计算 a^b](#1.3. pow(double a, double b):计算 a^b)
[2.1、log(double a):计算自然对数 ln(a)](#2.1、log(double a):计算自然对数 ln(a))
[2.2、log10(double a):计算以 10 为底的对数 log10(a)](#2.2、log10(double a):计算以 10 为底的对数 log10(a))
[2.3、log1p(double x):计算 ln(1 + x)](#2.3、log1p(double x):计算 ln(1 + x))
[3、符号与 ulp 操作](#3、符号与 ulp 操作)
[1. 衡量浮点数的 "接近程度"(替代直接相等判断)](#1. 衡量浮点数的 “接近程度”(替代直接相等判断))
[2. 分析数值算法的精度](#2. 分析数值算法的精度)
[3. 调试浮点计算异常](#3. 调试浮点计算异常)
在 Java 编程中,数值计算是一项基础且核心的任务。无论是简单的加减乘除,还是复杂的三角函数、指数运算,Java 标准库都为我们提供了一个强大的工具 ------java.lang.Math 类。这个类包含了大量用于执行基本数值运算的静态方法,涵盖了从简单的绝对值计算到复杂的浮点运算等多个方面。
一、核心字段:自然常数与圆周率
Math类定义了两个常用的数学常数,它们是程序中进行科学计算的基础:
1. Math.E
表示自然对数的底数 e (约等于 ++2.71828++ ),是一个 double 类型的常量。
java
public class MathConstants {
public static void main(String[] args) {
System.out.println("圆周率 π: " + Math.PI); // 输出:3.141592653589793
// 示例:计算半径为 5 的圆的面积
double radius = 5;
double area = Math.PI * radius * radius;
System.out.println("圆的面积: " + area); // 输出:78.53981633974483
}
}
2. Math.PI
表示圆周率**π**(约等于 3.14159),同样是 **double**类型的常量,常用于几何计算。
java
public class MathConstants {
public static void main(String[] args) {
System.out.println("圆周率 π: " + Math.PI); // 输出:3.141592653589793
// 示例:计算半径为 5 的圆的面积
double radius = 5;
double area = Math.PI * radius * radius;
System.out.println("圆的面积: " + area); // 输出:78.53981633974483
}
}
二、基础运算方法
1.绝对值计算:**abs**系列方法
**abs**方法用于计算各种数值类型的绝对值,支持 int、long、float、double 四种类型:
方法签名 功能描述 static int abs(int a)返回 int 类型的绝对值 static long abs(long a)返回 long 类型的绝对值 static float abs(float a)返回 float 类型的绝对值 static double abs(double a)返回 double 类型的绝对值
示例代码:
java
public class MathAbsExample {
public static void main(String[] args) {
int intNum = -10;
long longNum = -10000000000L;
float floatNum = -3.14f;
double doubleNum = -2.71828;
System.out.println("int 绝对值: " + Math.abs(intNum)); // 输出:10
System.out.println("long 绝对值: " + Math.abs(longNum)); // 输出:10000000000
System.out.println("float 绝对值: " + Math.abs(floatNum)); // 输出:3.14
System.out.println("double 绝对值: " + Math.abs(doubleNum)); // 输出:2.71828
}
}
注意 :对于 ++int++类型,++Integer.MIN_VALUE++ (-2147483648)的绝对值是无法用 int 表示的(因为最大值为 2147483647),此时Math.abs(Integer.MIN_VALUE)** 会返回其本身(++仍为负数++ )。若需检测这种溢出情况,可使用 ++absExact++ 方法:
java
public class MathAbsExactExample {
public static void main(String[] args) {
try {
int minInt = Integer.MIN_VALUE;
System.out.println(Math.absExact(minInt)); // 抛出 ArithmeticException
} catch (ArithmeticException e) {
System.out.println("错误:绝对值溢出!" + e.getMessage());
}
}
}
2.加减乘除与精确运算
Math 类提供了普通的算术运算支持,同时为了应对溢出问题,引入了一系列带「Exact」后缀的方法,当运算结果溢出时会抛出***ArithmeticException***。
1. 加法:addExact
java
public class MathAddExactExample {
public static void main(String[] args) {
// 正常情况
int a = 1000000;
int b = 2000000;
System.out.println(Math.addExact(a, b)); // 输出:3000000
// 溢出情况
try {
int maxInt = Integer.MAX_VALUE;
System.out.println(Math.addExact(maxInt, 1)); // 抛出异常
} catch (ArithmeticException e) {
System.out.println("加法溢出:" + e.getMessage());
}
}
}
2. 减法:subtractExact
java
public class MathSubtractExactExample {
public static void main(String[] args) {
long x = 5000000000L;
long y = 3000000000L;
System.out.println(Math.subtractExact(x, y)); // 输出:2000000000
try {
long minLong = Long.MIN_VALUE;
System.out.println(Math.subtractExact(minLong, 1)); // 抛出异常
} catch (ArithmeticException e) {
System.out.println("减法溢出:" + e.getMessage());
}
}
}
3. 乘法
multiplyExact:返回乘积,溢出时抛出异常。multiplyFull:返回两个 int 的精确乘积(结果为 long,避免溢出)。
java
public class MathMultiplyExample {
public static void main(String[] args) {
// multiplyExact
int m = 123456;
int n = 789012;
try {
System.out.println(Math.multiplyExact(m, n)); // 结果可能溢出 int
} catch (ArithmeticException e) {
System.out.println("乘法溢出:" + e.getMessage());
}
// multiplyFull:安全计算 int 乘积(返回 long)
long product = Math.multiplyFull(m, n);
System.out.println("精确乘积(long):" + product); // 输出:97407519744
}
}
4.取整与舍入
在处理浮点数时,我们经常需要将其转换为整数,Math 类提供了多种取整方法,适用于不同场景:
1. ceil(double a):向上取整
返回大于或等于参数的最小整数(以 ++double++形式表示)。
java
System.out.println(Math.ceil(3.2)); // 输出:4.0
System.out.println(Math.ceil(-3.2)); // 输出:-3.0
System.out.println(Math.ceil(5.0)); // 输出:5.0
2. floor(double a):向下取整
返回小于或等于参数的最大整数(以 ++double++形式表示)。
java
System.out.println(Math.floor(3.8)); // 输出:3.0
System.out.println(Math.floor(-3.8)); // 输出:-4.0
System.out.println(Math.floor(5.0)); // 输出:5.0
3. rint(double a):四舍五入到最近整数(返回 double)
若参数距离两个整数等距,则返回偶数。
java
System.out.println(Math.rint(3.2)); // 输出:3.0
System.out.println(Math.rint(3.5)); // 输出:4.0(与 3.5 等距,取偶数)
System.out.println(Math.rint(4.5)); // 输出:4.0(与 4.5 等距,取偶数)
4. round:四舍五入到整数(返回 int 或 long)
round(float a):返回intround(double a):返回 long
java
System.out.println(Math.round(3.2f)); // 输出:3(int)
System.out.println(Math.round(3.8f)); // 输出:4(int)
System.out.println(Math.round(3.5)); // 输出:4(long)
System.out.println(Math.round(-3.5)); // 输出:-3(long,向正无穷大舍入)
3.三角函数与双曲线函数
Math 类提供了完整的三角函数支持,包括++正弦、余弦、正切及其反函数++,所有角度参数均以弧度为单位。
1.基本三角函数:sin、cos、tan
java
public class TrigonometryExample {
public static void main(String[] args) {
double angle = Math.PI / 6; // 30 度(π/6 弧度)
// 正弦
double sinVal = Math.sin(angle);
System.out.println("sin(30°) = " + sinVal); // 输出:0.5(近似)
// 余弦
double cosVal = Math.cos(angle);
System.out.println("cos(30°) = " + cosVal); // 输出:0.8660254...(√3/2 近似)
// 正切
double tanVal = Math.tan(angle);
System.out.println("tan(30°) = " + tanVal); // 输出:0.57735...(1/√3 近似)
}
}
2.角度与弧度转换
由于三角函数参数为弧度,可使用 toRadians(度转弧度)和 toDegrees(弧度转度)进行转换:
java
double degrees = 45;
double radians = Math.toRadians(degrees);
System.out.println(degrees + "度 = " + radians + "弧度"); // 输出:45.0度 = 0.785398...弧度
double rad = Math.PI / 2;
double deg = Math.toDegrees(rad);
System.out.println(rad + "弧度 = " + deg + "度"); // 输出:1.570796...弧度 = 90.0度
3.反三角函数:asin、acos、atan、atan2
java
public class InverseTrigExample {
public static void main(String[] args) {
// 反正弦(返回 [-π/2, π/2] 弧度)
double asin = Math.asin(0.5);
System.out.println("arcsin(0.5) = " + Math.toDegrees(asin) + "度"); // 输出:30.0度
// 反余弦(返回 [0, π] 弧度)
double acos = Math.acos(0.5);
System.out.println("arccos(0.5) = " + Math.toDegrees(acos) + "度"); // 输出:60.0度
// 反正切(返回 [-π/2, π/2] 弧度)
double atan = Math.atan(1);
System.out.println("arctan(1) = " + Math.toDegrees(atan) + "度"); // 输出:45.0度
// 坐标反正切(根据 (x,y) 计算角度,返回 [-π, π] 弧度)
double x = 1;
double y = 1;
double atan2 = Math.atan2(y, x);
System.out.println("atan2(" + y + "," + x + ") = " + Math.toDegrees(atan2) + "度"); // 输出:45.0度
}
}
4.双曲线函数:sinh、cosh、tanh
双曲线函数是三角函数的类比,基于指数函数定义:
java
public class HyperbolicExample {
public static void main(String[] args) {
double x = 1.0;
// 双曲正弦(sinh(x) = (e^x - e^-x)/2)
double sinh = Math.sinh(x);
System.out.println("sinh(1) = " + sinh); // 输出:1.1752011936438014
// 双曲余弦(cosh(x) = (e^x + e^-x)/2)
double cosh = Math.cosh(x);
System.out.println("cosh(1) = " + cosh); // 输出:1.5430806348152437
// 双曲正切(tanh(x) = sinh(x)/cosh(x))
double tanh = Math.tanh(x);
System.out.println("tanh(1) = " + tanh); // 输出:0.7615941559557649
}
}
4.指数与对数运算
1.指数运算:exp、expm1、pow
1.1. exp(double a):计算自然指数 e^a
java
System.out.println(Math.exp(1)); // 输出:2.718281828459045(e^1)
System.out.println(Math.exp(0)); // 输出:1.0(e^0)
1.2. expm1(double x):计算 e^x - 1
对于接近 0 的 x,该方法比 exp(x) - 1 更精确:
java
double x = 0.000001;
System.out.println(Math.exp(x) - 1); // 输出:1.0000005000001665e-06(精度较低)
System.out.println(Math.expm1(x)); // 输出:1.0000005000001667e-06(更精确)
1.3. pow(double a, double b):计算 a^b
java
System.out.println(Math.pow(2, 3)); // 输出:8.0(2^3)
System.out.println(Math.pow(10, -2)); // 输出:0.01(10^-2)
System.out.println(Math.pow(4, 0.5)); // 输出:2.0(4的平方根)
System.out.println(Math.pow(0, 0)); // 输出:1.0(特殊规定)
2.对数运算:log、log10、log1p
2.1、log(double a):计算自然对数 ln(a)
java
System.out.println(Math.log(Math.E)); // 输出:1.0(ln(e))
System.out.println(Math.log(1)); // 输出:0.0(ln(1))
2.2、log10(double a):计算以 10 为底的对数 log10(a)
java
System.out.println(Math.log10(100)); // 输出:2.0(log10(100))
System.out.println(Math.log10(0.1)); // 输出:-1.0(log10(0.1))
2.3、log1p(double x):计算 ln(1 + x)
对于接近 0 的 x,比 log(1 + x) 更精确:
java
double x = 0.000001;
System.out.println(Math.log(1 + x)); // 输出:9.999995000003333e-07(精度较低)
System.out.println(Math.log1p(x)); // 输出:9.999995000001666e-07(更精确)
三、其他实用方法
1、平方根与立方根:sqrt、cbrt
sqrt(double a):返回非负 double 的正平方根(正确舍入)。cbrt(double a):返回 double 的立方根(可正可负)。
2、随机数生成:random
Math.random() 返回一个++大于等于++ 0.0 ++且小于++ 1.0 的**++随机++** **++double++**值,每次调用返回不同结果:
java
// 生成 1-100 之间的随机整数
int randomInt = (int) (Math.random() * 100) + 1;
System.out.println("随机整数(1-100):" + randomInt);
注意 :
Math.random()是线程安全的,但在多线程环境下性能较差。若需高性能随机数,可考虑java.util.Random或***ThreadLocalRandom***。
3、符号与 ulp 操作
signum:返回参数的符号(正为 1.0,负为 -1.0,零为 0.0)。ulp:返回参数的 ulp(单位在最后一位)大小,用于衡量浮点精度。
java
// signum 示例
System.out.println(Math.signum(5.2)); // 输出:1.0
System.out.println(Math.signum(-3.8)); // 输出:-1.0
System.out.println(Math.signum(0.0)); // 输出:0.0
// ulp 示例
System.out.println(Math.ulp(1.0)); // 输出:2.220446049250313e-16(1.0 的 ulp)
System.out.println(Math.ulp(1000000.0)); // 输出:0.0001220703125(大数的 ulp 更大,精度更低)
ulp全称 Unit in the Last Place(最后一位的单位),是衡量浮点数精度的核心指标。
浮点数(如float、double)在计算机中是离散表示 的(而非连续的实数),因为它们的存储位数有限(例如 IEEE 754 单精度浮点数用 23 位表示尾数,双精度用 52 位)。这意味着:两个相邻的、可被精确表示的浮点数之间存在一个最小差值 ,这个差值就是该浮点数的ulp。举个例子:
- 对于单精度浮点数(
float):
当数值较小时(如1.0f),相邻可表示的浮点数非常接近,ulp(1.0f)约为1.19e-7(即 2−23,因为单精度尾数是 23 位);
当数值很大时(如 223 附近),ulp会变大(此时ulp(2^23)为1.0f),因为尾数的有限位数无法再表示更小的间隔 ------ 这就是浮点数 "精度随数值增大而下降" 的原因。
ulp是浮点数精度的 "尺子",主要用于数值计算的误差分析 和合理比较浮点数,具体场景包括:1. 衡量浮点数的 "接近程度"(替代直接相等判断)
浮点数计算中,由于舍入误差(如
0.1 + 0.2不等于0.3),直接用==比较是否相等往往不准确。此时可以用ulp判断两个数是否 "足够接近":如果两个数的差值小于 k 倍的
ulp(k 通常取 1 或 2),则认为它们在数值上是等效的。
java// 判断 a 和 b 是否接近(差值 < 2 倍 ulp) boolean isClose(double a, double b) { return Math.abs(a - b) < 2 * Math.ulp(Math.min(a, b)); }2. 分析数值算法的精度
在科学计算(如物理模拟、工程计算)中,需要评估算法的误差是否在可接受范围内。
ulp可以量化误差大小:
- 若计算结果与理论值的差值在 1-2 个
ulp内,说明算法精度极高(接近浮点数的理论极限);- 若误差达到 100 个
ulp以上,可能需要优化算法(如减少舍入累积)。3. 调试浮点计算异常
当数值计算出现 "奇怪的偏差" 时,
ulp可以帮助定位问题:例如,若一个本应精确的计算(如
2.0 / 2.0)结果与理论值的差值超过 1 个ulp,可能是代码中存在类型转换错误(如float和double混用)或溢出。
signum函数的作用是提取数值的 "符号信息"(正 / 负 / 零),实际用途集中在 "需要根据方向做决策" 的场景
四、资料来源
还有一些我会继续加入进来的......