Java 每日一刊(第7期):浮点数运算


“计算机程序的错误通常在于数值近似。”

前言

这里是分享 Java 相关内容的专刊,每日一更。

本期将为大家带来以下内容:

  1. Java 的浮点数类型
  2. 基本的浮点数运算符
  3. 浮点数除法与取模
  4. 自增与自减运算
  5. 浮点数的科学计数法表示
  6. 浮点数的精度问题
  7. 解决浮点数精度问题
  8. 浮点数溢出问题
  9. 类型自动提升(Type Promotion)
  10. 强制类型转换(Type Casting)

Java 的浮点数类型

Java 是一种强类型语言,变量在声明时必须指定类型。对于浮点数运算,Java 提供了以下几种基本数据类型:

类型大小精度(有效位数)最小值最大值
float4 字节大约 7 位有效数字 1.4 × 1 0 − 45 1.4 \times 10^{-45} 1.4×1045 3.4 × 1 0 38 3.4 \times 10^{38} 3.4×1038
double8 字节大约 15 位有效数字 4.9 × 1 0 − 324 4.9 \times 10^{-324} 4.9×10324 1.7 × 1 0 308 1.7 \times 10^{308} 1.7×10308
  • float:单精度浮点数,使用 32 位来存储,适合对内存要求较高或精度要求较低的场景。
  • double:双精度浮点数,使用 64 位来存储,是 Java 中的默认浮点数类型,适用于大多数科学计算和高精度运算。

通常,Java 默认将小数类型识别为 double。如果需要定义 float 类型的数值,必须在数值后加上 fF 后缀。

基本的浮点数运算符

Java 中的基本整数运算符与其他主流编程语言类似,支持的操作包括加、减、乘、除等。以下是 Java 支持的整数运算符:

  • + :加法
  • - :减法
  • * :乘法
  • / :除法
  • % :取模(求余)
double a = 5.7;
double b = 2.3;

System.out.println("加法: " + (a + b));  // 输出: 8.0
System.out.println("减法: " + (a - b));  // 输出: 3.4
System.out.println("乘法: " + (a * b));  // 输出: 13.11
System.out.println("除法: " + (a / b));  // 输出: 2.4782608695652173
System.out.println("取模: " + (a % b));  // 输出: 1.1000000000000005

浮点数除法与取模

浮点数除法不同于整数除法,它会保留小数部分。例如,10.0 / 3.0 的结果为 3.3333333333333335。取模运算同样适用于浮点数,返回的是除法后的余数。

double result = 10.0 / 3.0;     // 结果是 3.3333333333333335
double remainder = 10.0 % 3.0;  // 余数是 1.0

自增与自减运算

Java 同样支持对浮点数的自增(++)和自减(--)操作。与整数类型类似,浮点数的自增自减操作也有前置与后置之分:

  • 前置:先增加/减少,再返回值。
  • 后置:先返回值,再增加/减少。
double a = 1.5;
double b = ++a;  // 先将 a 加 1(a 变为 2.5),然后将结果赋值给 b,所以 b 的值为 2.5
System.out.println("前置自增后的 a: " + a);  // 输出: 2.5
System.out.println("前置自增后的 b: " + b);  // 输出: 2.5

double c = 1.5;
double d = c++;  // 先将 c 的当前值(1.5)赋给 d,然后再将 c 加 1(c 变为 2.5)
System.out.println("后置自增后的 c: " + c);  // 输出: 2.5
System.out.println("后置自增后的 d: " + d);  // 输出: 1.5

double e = 2.5;
double f = --e;  // 先将 e 减 1(e 变为 1.5),然后将结果赋值给 f,所以 f 的值为 1.5
System.out.println("前置自减后的 e: " + e);  // 输出: 1.5
System.out.println("前置自减后的 f: " + f);  // 输出: 1.5

double g = 2.5;
double h = g--;  // 先将 g 的当前值(2.5)赋给 h,然后再将 g 减 1(g 变为 1.5)
System.out.println("后置自减后的 g: " + g);  // 输出: 1.5
System.out.println("后置自减后的 h: " + h);  // 输出: 2.5

浮点数的科学计数法表示

Java 支持用科学计数法表示浮点数,尤其适合表示非常大的或非常小的数。例如,1.23e10 代表 1.23 × 1 0 10 1.23 \times 10^{10} 1.23×10101.23e-10 代表 1.23 × 1 0 − 10 1.23 \times 10^{-10} 1.23×1010

double large = 1.23e10;  // 1.23 * 10^10
double small = 1.23e-10; // 1.23 * 10^-10

System.out.println("large = " + large);  // 输出: 1.23E10
System.out.println("small = " + small);  // 输出: 1.23E-10

浮点数的精度问题

浮点数的精度是一个常见问题,尤其是在处理非常小的数或无法精确表示的数时(如 0.1 和 0.2)。由于浮点数是以二进制表示的,因此某些十进制的小数在浮点数中无法精确表示,可能会导致精度丢失。

double a = 0.1;
double b = 0.2;
System.out.println("0.1 + 0.2 = " + (a + b));  // 输出: 0.30000000000000004

解决浮点数精度问题

在一些对精度要求很高的场景中(如金融计算),可以使用 BigDecimal 类来避免浮点数的精度问题。

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
System.out.println("0.1 + 0.2 = " + a.add(b));  // 输出: 0.3

浮点数溢出问题

浮点数虽然范围很大,但仍然有极限。当浮点数超出其表示范围时,会出现溢出问题。Java 对于溢出的处理方式不同于整数,它会返回 Infinity-Infinity,而不是像整数那样回绕。

double large = 1.7E308;
double result = large * 10;
System.out.println("Overflow result: " + result);  // 输出: Infinity

类型自动提升(Type Promotion)

类型自动提升是指在表达式中,当参与运算的不同数据类型不一致时,Java 自动将较小的类型提升为较大的类型,以避免数据丢失。通常,这种提升遵循从低精度到高精度的顺序:

byte → short → int → long → float → double

float f = 2.5f;
int i = 10;
double result = f + i;  // int 自动提升为 float,然后结果再提升为 double
System.out.println("运算结果: " + result);  // 输出: 12.5

在上述示例中,int 类型的 i 自动提升为 float

强制类型转换(Type Casting)

强制类型转换是将一个数据类型的值显式转换为另一个类型的过程。这通常用于将高精度的类型转换为低精度类型(比如将 double 转换为 int),或者在需要进行特定的类型转换时使用。强制转换可能会导致数据丢失,因此需要格外小心。

double d = 5.99;
int i = (int) d;  // 强制类型转换为 int,舍去小数部分
System.out.println("强制转换结果: " + i);  // 输出: 5

本期小知识

尽量避免在循环控制、比较等对精度要求较高的场景下使用浮点数,因为它们的精度限制和误差可能导致意外行为。在这种情况下,使用整数类型或 BigDecimal 会更安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值