有人可以告诉我为什么此代码不起作用吗?我正在尝试以给定的精度限制实现正弦函数(通过误差变量)。
此处提供了有关计算的某些详细信息:https://en.wikipedia.org/wiki/Taylor_series
berechnePot计算效能 berechneFak计算师资 berechneVZW计算前置符号(正负)
我不明白为什么函数要计算的这么慢。
public class Sinus {
public static double sinus(double x) {
double error = 0.001;
double summand = 0;
double sum = 0;
int k = 0;
do {
double pot = 0;
double fak = 0;
pot = berechnePot(x, k);
fak = berechneFak(k);
summand = pot / fak;
berechneVZW(summand, k);
sum += summand;
k++;
} while (abs(summand) > error);
return sum;
}
public static double abs(double value) {
if (value < 0) return -value;
else return value;
}
public static double berechneVZW(double value, int k) {
if (k % 2 == 0) {
return value;
} else {
return value *= (-1);
}
}
public static double berechnePot(double x, double k) {
double pot = 0;
pot += x;
for (int i = 0; i <= k; i++) {
pot *= (x * x);
}
return pot;
}
public static double berechneFak(int k) {
double fak = 1;
if (k == 0) {
return 1;
} else {
for (int i = 0; i <= k; k++) {
fak *= (2 * i + 1);
}
}
return fak;
}
}
最后我找到了正确的解决方案。
我希望新的结构可以帮助您更好地理解我的实现。
感谢您的所有帮助!
public class Sinus {
public static double sinus(double x) {
double error = 0.00001;
double summand = 0;
double result = 0;
double fak = 0;
int k = 0;
do {
double pot = 0;
pot = calcNumeratorPotency(x, k);
fak = calcDenumeratorFaculty(k);
summand = pot / fak;
summand = definePreSign(summand, k);
result += summand;
k++;
} while (absoluteValue(summand) > error);
return result;
}
public static double absoluteValue(double value) {
if (value < 0)
return -value;
else
return value;
}
public static double definePreSign(double value, int k) {
if (k % 2 == 0) {
return value;
} else {
return value * (-1);
}
}
public static double calcNumeratorPotency(double x, double k) {
double pot = x;
for (int i = 0; i < 2 * k; i++) {
pot *= x;
}
return pot;
}
public static double calcDenumeratorFaculty(int k) {
double fak = 1;
if (k == 0) {
return 1;
} else {
for (int i = 1; i <= (2 * k + 1); i++) {
fak *= i;
}
}
return fak;
}
答案 0 :(得分:3)
您以前似乎曾经使用过另一种语言。 Java的工作与您预期的有所不同。
for (int i = 0; i <= k; k++) {
fak *= (2 * i + 1);
}
此特定循环肯定无法按预期工作。您增加了k
,但是i
应该增长了吗?可能是您要写的:
for (int i = 0; i <= k; i++) {
fak *= (2 * i + 1);
}
因为循环计数为k
,而不是i
,所以循环继续,直到k超出整数范围并变为Integer.MIN_VALUE
。到那时,您的循环终于终止了。 :)
另一个完全不同的注释,它是一种建设性的批评:您可能想看看默认的Java样式指南(https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/styleguide.md)
小节录:
// Bad.
// - This offers poor visual separation of operations.
int foo=a+b+1;
// Good.
int foo = a + b + 1;
标识符和运算符之间的空格非常有用,既可以用数字进行运算,又可以使用很多不同的东西。
答案 1 :(得分:2)
我不太清楚您在berechnePot
和berechnePot
中所计算的内容。从上下文来看,它们似乎是分子和分母。
使用调试器运行代码,我发现summand
的计算非常错误,并且递减速度非常慢。这就是为什么要花这么长时间的原因。
Math
类提供了一种pow
方法,因此您实际上并不需要使用for循环来计算功效。我认为您可能会使这个问题变得过于复杂。我会写一个getSummand
方法和一个factorial
方法:
private static double getSummand(double x, int k) {
int power = k * 2 + 1;
double numerator = Math.pow(x, power);
double denominator = factorial(power);
int sign = k % 2 == 1 ? -1 : 1;
return numerator / denominator * sign;
}
private static double factorial(int x) {
double result = 1;
for (int i = 1; i <= x; i++) {
result *= i;
}
return result;
}
并像这样使用它们:
public static double sinus(double x) {
double error = 0.001;
double summand = 0;
double sum = 0;
int k = 0;
do {
summand = getSummand(x, k);
sum += summand;
k++;
} while (Math.abs(summand) > error);
return sum;
}
如果这是一项分配,并且不允许您使用Math
类中的任何东西,则可以编写自己的pow
方法,如下所示:
private static double pow(double x, int p) {
double result = 1;
for (int i = 0 ; i < p ; i++) {
result *= x;
}
return result;
}
答案 2 :(得分:2)
在berechneFak()
函数中,else
子句中有一个循环。您确实增加了k
而不是i
,所以i <= k
始终为真。尝试在调试器中查看它。这是使速度变慢的循环。
因此,每次k
都会以单个增量计算最大整数值2,147,483,647,然后溢出到负值,此时循环将结束。
只需澄清一下:我不是在看数学是否正确,而只是在看程序为什么运行缓慢。