当前位置: 首页 > news >正文

Java 数学工具类 Math

目录

一、核心字段:自然常数与圆周率

1. Math.E

2. Math.PI

二、基础运算方法

1.绝对值计算:abs 系列方法

2.加减乘除与精确运算

1. 加法:addExact

2. 减法:subtractExact

3. 乘法

4.取整与舍入

1. ceil(double a):向上取整

2. floor(double a):向下取整

3. rint(double a):四舍五入到最近整数(返回 double)

4. round:四舍五入到整数(返回 int 或 long)

3.三角函数与双曲线函数

1.基本三角函数:sin、cos、tan

2.角度与弧度转换

3.反三角函数:asin、acos、atan、atan2

4.双曲线函数:sinh、cosh、tanh

4.指数与对数运算

1.指数运算:exp、expm1、pow

1.1. exp(double a):计算自然指数 e^a

1.2. expm1(double x):计算 e^x - 1

1.3. pow(double a, double b):计算 a^b

2.对数运算:log、log10、log1p

2.1、log(double a):计算自然对数 ln(a)

2.2、log10(double a):计算以 10 为底的对数 log10(a)

2.3、log1p(double x):计算 ln(1 + x)

三、其他实用方法

1、平方根与立方根:sqrt、cbrt

2、随机数生成:random

3、符号与 ulp 操作

1. 衡量浮点数的 “接近程度”(替代直接相等判断)

2. 分析数值算法的精度

3. 调试浮点计算异常

四、资料来源


在 Java 编程中,数值计算是一项基础且核心的任务。无论是简单的加减乘除,还是复杂的三角函数、指数运算,Java 标准库都为我们提供了一个强大的工具 ——java.lang.Math 类。这个类包含了大量用于执行基本数值运算的静态方法,涵盖了从简单的绝对值计算到复杂的浮点运算等多个方面。

一、核心字段:自然常数与圆周率

Math 类定义了两个常用的数学常数,它们是程序中进行科学计算的基础:

1. Math.E

表示自然对数的底数 e(约等于 2.71828),是一个 double 类型的常量。

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 类型的常量,常用于几何计算。

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 方法用于计算各种数值类型的绝对值,支持 intlongfloatdouble 四种类型:

方法签名功能描述
static int abs(int a)返回 int 类型的绝对值
static long abs(long a)返回 long 类型的绝对值
static float abs(float a)返回 float 类型的绝对值
static double abs(double a)返回 double 类型的绝对值

示例代码

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)); // 输出:10System.out.println("long 绝对值: " + Math.abs(longNum)); // 输出:10000000000System.out.println("float 绝对值: " + Math.abs(floatNum)); // 输出:3.14System.out.println("double 绝对值: " + Math.abs(doubleNum)); // 输出:2.71828}
}

注意:对于 int 类型,Integer.MIN_VALUE(-2147483648)的绝对值是无法用 int 表示的(因为最大值为 2147483647),此时 Math.abs(Integer.MIN_VALUE) 会返回其本身(仍为负数)。若需检测这种溢出情况,可使用 absExact 方法:

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

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

public class MathSubtractExactExample {public static void main(String[] args) {long x = 5000000000L;long y = 3000000000L;System.out.println(Math.subtractExact(x, y)); // 输出:2000000000try {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,避免溢出)。
public class MathMultiplyExample {public static void main(String[] args) {// multiplyExactint 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 形式表示)。

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 形式表示)。

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)

若参数距离两个整数等距,则返回偶数。

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):返回 int
  • round(double a):返回 long
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.基本三角函数:sincostan

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(弧度转度)进行转换:

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.反三角函数:asinacosatanatan2

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.双曲线函数:sinhcoshtanh

双曲线函数是三角函数的类比,基于指数函数定义:

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.指数运算:expexpm1pow

1.1. exp(double a):计算自然指数 e^a
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 更精确:

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
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.对数运算:loglog10log1p

2.1、log(double a):计算自然对数 ln(a)
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)
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) 更精确:

double x = 0.000001;
System.out.println(Math.log(1 + x)); // 输出:9.999995000003333e-07(精度较低)
System.out.println(Math.log1p(x)); // 输出:9.999995000001666e-07(更精确)

三、其他实用方法

1、平方根与立方根:sqrtcbrt

  • sqrt(double a):返回非负 double 的正平方根(正确舍入)。
  • cbrt(double a):返回 double 的立方根(可正可负)。

2、随机数生成:random

Math.random() 返回一个大于等于 0.0 且小于 1.0 的随机 double 值,每次调用返回不同结果:

// 生成 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(单位在最后一位)大小,用于衡量浮点精度。
// 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(最后一位的单位),是衡量浮点数精度的核心指标。

浮点数(如 floatdouble)在计算机中是离散表示的(而非连续的实数),因为它们的存储位数有限(例如 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),则认为它们在数值上是等效的。

// 判断 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 函数的作用是提取数值的 “符号信息”(正 / 负 / 零),实际用途集中在 “需要根据方向做决策” 的场景

四、资料来源 

Math类

还有一些我会继续加入进来的……

http://www.xdnf.cn/news/1205983.html

相关文章:

  • redis未授权getshell四种方式
  • Leetcode——11. 盛最多水的容器
  • 利用DataStream和TrafficPeak实现大数据可观察性
  • 【Git】Linux-ubuntu 22.04 初步认识 -> 安装 -> 基础操作
  • Prompt工程记录
  • MCU+RTOS调试
  • STM32启动流程
  • opencv 模块裁剪 按需安装指定模块
  • MCU 中的 PWM(脉冲宽度调制)是什么?
  • 未授权访问复现
  • Python动态规划:从基础到高阶优化的全面指南
  • 未授权访问漏洞靶场(redis,MongoDB,Memcached...)
  • Unity_UI_NGUI_锚点组件
  • 项目如何按时交付?重点关注的几点
  • 【Linux操作系统】简学深悟启示录:Linux环境基础开发工具使用
  • GoLand 项目从 0 到 1:第三天 —— 图数据库版本管理方案调研与中间件部署
  • Dify-14: 工作流API端点
  • 在虚拟机ubuntu上修改framebuffer桌面不能显示图像
  • STM32F4—电源管理器
  • YOLOv11改进:添加SCConv空间和通道重构卷积二次创新C3k2
  • 时间数字转换器TDC的FPGA方案及核心代码
  • 数分思维10:用户增长
  • 小智源码分析——音频部分(二)
  • 机器学习sklearn:决策树的参数、属性、接口
  • mp核心功能
  • S7-200 SMART 通过本体 RS485 口与 DP01 上传 / 下载程序(网口故障)
  • Java项目:基于SSM框架实现的进销存管理系统【ssm+B/S架构+源码+数据库+毕业论文+远程部署】
  • 我从 Web2 转型到 Web3 的 9 条经验总结
  • 架构实战——互联网架构模板(“存储层”技术)
  • fchown/fchownat系统调用及示例