Java循环计算至第8轮结果为负、Math.abs不生效的问题咨询
Java复利计算场景下循环输出负数、
Math.abs失效问题 复现代码
import java.text.NumberFormat; import java.util.Scanner; public class Main { public static void main(String[] args) { float yearlyReturn = 200f; int totalGain = 0; int monthlyPayOut = 100000; int yearsWaiting = 8; int firstMoney = 0; float returnGet = (1 + yearlyReturn/100); totalGain += firstMoney; for (int i = 0; i < yearsWaiting; i++){ totalGain += (monthlyPayOut * 12); totalGain *= returnGet; System.out.println(totalGain); if (totalGain < 0){ totalGain = Math.abs(totalGain); System.out.println(totalGain); } } } }
现象说明
- 循环前几轮的计算结果符合预期数值
- 执行到第8轮循环时,控制台输出负数结果
- 尝试通过
Math.abs将负数转正,没有达到预期效果
问题原因解答
为什么第8轮循环会输出负数
根本原因是Java int类型的整数溢出:
- 代码中
totalGain定义为32位有符号int类型,取值范围固定为-2147483648 ~ 2147483647 - 场景中年收益率为200%,对应每年资产值翻3倍,叠加每年120万的定投入金,资产值会快速指数增长:
- 第6轮循环结束时的资产值已经达到13.1亿,接近int类型的上限
- 第7轮循环计算时,单步运算结果就已经超过int类型的最大正值上限,按照32位有符号整数的补码存储规则,溢出后高位的符号位会被置1,直接进入负数的数值区间,最终在控制台输出负数
Math.abs的工作机制
- 核心逻辑是对传入的参数取对应数值的非负等价形式返回,匹配传入参数的类型(支持int、long、float、double四类数值类型入参)
- 存在固定的边界限制:当传入的参数是对应整数类型能表示的最小负值(比如int类型的最小边界值
-2147483648)时,因为该类型没有足够的数值空间存储这个值对应的正数,Math.abs的返回值依然是这个最小负数本身,无法完成转正 - 本案例中
Math.abs未达预期的原因:整数溢出后生成的负数,大概率落在int类型的最小边界区间,触发了abs方法的边界限制;同时本质问题是用取值范围不足的int类型存储高增长的计算值,从根源上导致了计算异常
内容的提问来源于stack exchange,提问作者KATA
相关产品推荐
相关产品推荐

