使用 BigDecimals 和 Nilakantha 系列计算 pi 不适用于超过 10 位小数
Calculating pi using BigDecimals and the Nilakantha series does not work for more than 10 decimal places
这是我的代码:
import java.math.BigDecimal;
public class Challenge6 {
private static final String PI = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295";
public static BigDecimal calculatePi(int decimals) {
BigDecimal pi = new BigDecimal(3);
boolean toggle = true;
boolean enough = false;
int i = 2;
while (!enough) {
BigDecimal num = new BigDecimal(
(double) (4 / (double) (i * (i + 1) * (i + 2))));
System.out.println(i / 2);
if (toggle) {
pi = pi.add(num);
toggle = false;
} else {
pi = pi.subtract(num);
toggle = true;
}
i += 2;
try {
if (PI.substring(0, decimals + 2).equals(
("" + pi).substring(0, decimals + 2))) {
enough = true;
} else {
}
} catch (Exception ex) {
continue;
}
}
return pi;
}
public static void main(String[] args) {
System.out.printf("Pi: %.30s", calculatePi(10));
}
}
我知道它并不完美,但这只是为了好玩。我只是想知道为什么我的程序可以在 700 多次迭代中完美地生成小数点后 10 位的圆周率,但是当我尝试计算超过 10 位时,它会永远持续(至少我假设永远)。这仅仅是由于浮点除法还是其他原因?如果是这样,为什么它在 10 点后 停止 工作?此外,如果您 运行 程序在每次迭代时打印出 pi,它会变成类似 3.39 的值。 BigDecimal 在这里有问题,还是我的代码有问题?任何帮助都会很酷。
P.S。 - 我真的只需要小数点后 30 位。
您使用 BigDecimal class 的方式没有任何作用。双倍除法(以及分母变大时的精度)将是您的限制因素。
尝试使用 BigDecimal 组件执行所有这些操作,这些组件使用 BigDecimal 运算进行除法——您可能还想在分母中使用 BigDecimal 组件。
实际上你可以把分母变成一个long,然后只用一个BigNum除法运算直到long溢出。我建议不要使用 Double 或其他任何东西作为分母,因为您将无法检测到精度损失。
当您使用表达式 "new BigDecimal( (double) (4 / (double) (i * (i + 1) * (i + 2))))" 时,您使用的是 double,而不是 BigDecimal。并且使用 double ins't posible 有足够的规模来计算超过 10 位小数。
使用以下代码
public static BigDecimal calculatePi(int decimals) {
BigDecimal pi = new BigDecimal(3);
boolean toggle = true;
boolean enough = false;
int i = 2;
while (!enough) {
BigDecimal a = new BigDecimal(4); // All operation must be using only BigDecimal
BigDecimal b = new BigDecimal(i).multiply(new BigDecimal(i + 1)).multiply(new BigDecimal(i + 2));
BigDecimal num = a.divide(b, 100, RoundingMode.FLOOR);
System.out.println(i / 2);
if (toggle) {
pi = pi.add(num);
toggle = false;
} else {
pi = pi.subtract(num);
toggle = true;
}
i += 2;
if (PI.substring(0, decimals + 2).equals(("" + pi).substring(0, decimals + 2))) {
enough = true;
}
}
return pi;
}
P.S.我检查这个代码是20位小数,但是30位小数你需要等待很多时间,我想
这是我的代码:
import java.math.BigDecimal;
public class Challenge6 {
private static final String PI = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295";
public static BigDecimal calculatePi(int decimals) {
BigDecimal pi = new BigDecimal(3);
boolean toggle = true;
boolean enough = false;
int i = 2;
while (!enough) {
BigDecimal num = new BigDecimal(
(double) (4 / (double) (i * (i + 1) * (i + 2))));
System.out.println(i / 2);
if (toggle) {
pi = pi.add(num);
toggle = false;
} else {
pi = pi.subtract(num);
toggle = true;
}
i += 2;
try {
if (PI.substring(0, decimals + 2).equals(
("" + pi).substring(0, decimals + 2))) {
enough = true;
} else {
}
} catch (Exception ex) {
continue;
}
}
return pi;
}
public static void main(String[] args) {
System.out.printf("Pi: %.30s", calculatePi(10));
}
}
我知道它并不完美,但这只是为了好玩。我只是想知道为什么我的程序可以在 700 多次迭代中完美地生成小数点后 10 位的圆周率,但是当我尝试计算超过 10 位时,它会永远持续(至少我假设永远)。这仅仅是由于浮点除法还是其他原因?如果是这样,为什么它在 10 点后 停止 工作?此外,如果您 运行 程序在每次迭代时打印出 pi,它会变成类似 3.39 的值。 BigDecimal 在这里有问题,还是我的代码有问题?任何帮助都会很酷。
P.S。 - 我真的只需要小数点后 30 位。
您使用 BigDecimal class 的方式没有任何作用。双倍除法(以及分母变大时的精度)将是您的限制因素。
尝试使用 BigDecimal 组件执行所有这些操作,这些组件使用 BigDecimal 运算进行除法——您可能还想在分母中使用 BigDecimal 组件。
实际上你可以把分母变成一个long,然后只用一个BigNum除法运算直到long溢出。我建议不要使用 Double 或其他任何东西作为分母,因为您将无法检测到精度损失。
当您使用表达式 "new BigDecimal( (double) (4 / (double) (i * (i + 1) * (i + 2))))" 时,您使用的是 double,而不是 BigDecimal。并且使用 double ins't posible 有足够的规模来计算超过 10 位小数。
使用以下代码
public static BigDecimal calculatePi(int decimals) {
BigDecimal pi = new BigDecimal(3);
boolean toggle = true;
boolean enough = false;
int i = 2;
while (!enough) {
BigDecimal a = new BigDecimal(4); // All operation must be using only BigDecimal
BigDecimal b = new BigDecimal(i).multiply(new BigDecimal(i + 1)).multiply(new BigDecimal(i + 2));
BigDecimal num = a.divide(b, 100, RoundingMode.FLOOR);
System.out.println(i / 2);
if (toggle) {
pi = pi.add(num);
toggle = false;
} else {
pi = pi.subtract(num);
toggle = true;
}
i += 2;
if (PI.substring(0, decimals + 2).equals(("" + pi).substring(0, decimals + 2))) {
enough = true;
}
}
return pi;
}
P.S.我检查这个代码是20位小数,但是30位小数你需要等待很多时间,我想