基于舍入π的算术计算中x1与x2仅特定precision相等的原因咨询
precision值下x1 == x2成立? 咱们先把代码里的逻辑拆明白,再一步步推导背后的原因——你观察到的x1+x2始终等于PI/precision是个非常关键的线索,先从这里入手:
1. 先搞懂变量到底代表什么
先明确几个核心变量的实际含义:
PI = (int) Math.round(Math.PI * precision):这其实是把π放大precision倍后四舍五入取整,反过来PI/precision就是π四舍五入到precision位小数的近似值(比如precision=2时,π*2≈6.28,取整后是6,6/2=3.0就是π保留2位小数的近似值)。x1 = makePrecise(Math.PI / 2):把π/2也四舍五入到precision位小数的结果。x2 = makePrecise(PI / precision - Math.PI / 2):用π的近似值减去真实的π/2,再把这个差值四舍五入到precision位小数。
2. 为什么x1 + x2永远等于PI/precision?
makePrecise(num)的本质就是把num乘以precision后四舍五入,再除以precision,说白了就是给num保留precision位小数(或者说精确到1/precision的精度)。
假设a = Math.PI/2,b = PI/precision - Math.PI/2,那显然a + b = PI/precision——这个值是个整数除以precision的分数,是precision位小数的精确值(比如precision=3时就是9/3=3.0)。
现在看a*precision + b*precision = (a+b)*precision = PI,这是个整数。如果a*precision的整数部分是m,小数部分是f(0≤f<1),那b*precision的整数部分就是PI - m,小数部分是1 - f(因为两个小数部分加起来刚好是1,才能让总和是整数)。
那四舍五入之后:
- 如果
f < 0.5,a*precision四舍五入是m,b*precision的小数部分1-f > 0.5,四舍五入是(PI - m) + 1,加起来就是m + (PI - m) +1 = PI; - 如果
f > 0.5,a*precision四舍五入是m+1,b*precision的小数部分1-f <0.5,四舍五入是PI - m,加起来也是(m+1)+(PI -m)=PI; - 哪怕
f=0.5(Java用的是银行家舍入,小数部分0.5时取最近的偶数),两者四舍五入后的和依然是PI——比如a*precision=4.5(四舍五入为4,因为4是偶数),b*precision=4.5(四舍五入为4),加起来8,刚好等于PI=8。
所以把这两个四舍五入的结果除以precision,加起来就是PI/precision,这就是为什么x1+x2永远等于这个值。
3. 为什么只有特定precision下x1 == x2?
x1 == x2等价于它们四舍五入后的整数部分相等(因为都除以precision),也就是:
round(Math.PI/2 * precision) == round( (PI/precision - Math.PI/2) * precision )
把右边化简一下,就是round(PI - Math.PI/2 * precision),而PI是round(Math.PI * precision),我们设Q = Math.PI * precision,那PI = round(Q),代入后问题就变成:
round(Q/2) == round( round(Q) - Q/2 )
再设round(Q) = Q + ε,这里的ε就是四舍五入的误差,范围是-0.5 ≤ ε < 0.5(当Q是半整数时,比如3.5,ε就是+0.5;2.5的话ε是-0.5,因为Java取偶数)。代入后式子变成:
round(Q/2) == round(Q/2 + ε)
这个等式成立与否,完全看Q/2的小数部分和ε的大小:
- 如果
Q/2的小数部分离0.5很远,比如0.1或者0.8,那ε的波动(最多±0.5)不会改变四舍五入的结果,等式就成立; - 如果
Q/2的小数部分接近0.5,比如0.49或者0.51,那ε的正负就会让四舍五入的结果跳变,等式就不成立。
但Q = Math.PI * precision,π是无理数啊!它的小数部分是无限不循环的,所以π*precision的小数部分也是完全无规律的——随着precision增大,Q的小数部分不会重复出现固定模式,ε的取值也就毫无规律,自然x1 == x2的precision值看起来就没什么明显规律了。
举两个实际例子:
precision=2时,Q=π*2≈6.28,ε=-0.28,Q/2≈3.14(小数部分0.14),Q/2+ε≈2.86(小数部分0.86),两者四舍五入都是3,所以x1=x2=1.5;precision=3时,Q=π*3≈9.424,ε=-0.424,Q/2≈4.712(小数部分0.712,四舍五入为5),Q/2+ε≈4.288(小数部分0.288,四舍五入为4),所以x1≈1.666,x2≈1.333,两者不相等。
总结一下
x1 + x2始终等于PI/precision,是因为两个数四舍五入后的误差刚好抵消,加起来等于精确的近似值;- 只有特定
precision下x1 == x2,是因为π的无理数特性导致π*precision的小数部分完全无规律,进而让四舍五入误差是否会改变Q/2的舍入结果也没有固定规律。
内容的提问来源于stack exchange,提问作者Gaurang Tandon

