如何使用DecimalFormat?蒙特卡洛法求π值格式化异常求助
蒙特卡洛法计算π时结果异常的问题排查与修复
我尝试用蒙特卡洛法计算圆周率π的近似值,用DecimalFormat格式化结果,但最后一组输入(1000000000)的结果是0.314173,完全不符合预期。以下是我的实现代码和运行输出:
原代码
import java.util.Random; import java.util.ArrayList; import java.text.DecimalFormat; public class MonteCarlo{ public static void main(String[] args) { double m = 0, rnumber, result; int count = 0, choosenOne; Random generator = new Random(); DecimalFormat fmt = new DecimalFormat("#.######"); ArrayList<Integer> n = new ArrayList<Integer>(); n.add(100); n.add(10000); n.add(1000000); n.add(100000000); n.add(1000000000); for (int i = 1; i <= 5; i++) { choosenOne = n.get(i - 1); while (count <= choosenOne * 4) { rnumber = generator.nextDouble(4); if (rnumber <= Math.PI) m++; count++; } result = m / choosenOne; System.out.println(choosenOne + ": " + fmt.format(result)); } } }
原运行输出
100: 3.14
10000: 3.1379
1000000: 3.141689
100000000: 3.141726
1000000000: 0.314173
问题分析
- 整数溢出:
choosenOne是int类型,当取值为1000000000时,choosenOne * 4等于4000000000,超出了int类型的最大值(2147483647),触发整数溢出后结果变为负数。此时count是前几次循环累计的大数,远大于负数,导致最后一次循环的while体完全不执行,m没有新增计数,但choosenOne是10倍于前一次的数值,最终结果被缩小10倍。 - 变量未重置:
m和count定义在循环外部,每次迭代会累加之前的结果,不符合蒙特卡洛法每次独立实验的要求,导致后续实验的样本基数混乱。
修复方案
- 将样本数量类型改为
long,避免乘法运算时的整数溢出; - 将计数变量
m和count移到for循环内部,每次迭代重置为0,保证实验独立性; - 优化循环逻辑,用
for循环替代while,可读性更强。
修复后的代码
import java.util.Random; import java.util.ArrayList; import java.text.DecimalFormat; public class MonteCarlo { public static void main(String[] args) { DecimalFormat fmt = new DecimalFormat("#.######"); ArrayList<Long> n = new ArrayList<>(); n.add(100L); n.add(10000L); n.add(1000000L); n.add(100000000L); n.add(1000000000L); Random generator = new Random(); for (Long choosenOne : n) { double hitCount = 0; long totalTrials = choosenOne * 4; // 用for循环替代while,逻辑更清晰 for (long i = 0; i < totalTrials; i++) { double rnumber = generator.nextDouble(4); if (rnumber <= Math.PI) { hitCount++; } } double result = hitCount / choosenOne; System.out.println(choosenOne + ": " + fmt.format(result)); } } }
修复后预期输出
每次实验独立运行,最后一组结果会回到π的合理近似区间,示例输出:
100: 3.12
10000: 3.1452
1000000: 3.141508
100000000: 3.141602
1000000000: 3.141593
内容的提问来源于stack exchange,提问作者Arson1st
相关产品推荐
相关产品推荐

