I was asked to find the cos following this equation:
I was able to find the sin of the angle, however when finding the cos, the number I would get is quite different from the correct value:
I used the following code for finding the cos.
ps: I can't use math.cos
public static double cos(double x, int n){
// declaring cos and factorial
double cos = 0.0;
// this loop determines how long does the loop go so the answer is more accurate
for (long howlong = 1 ; howlong <=n; howlong++){
double factorial =1;
// this will calculate the factorial for even numbers ex/ 2*2 = 4 , 4-2 = 2
// for the denominator
for (int factorialnumber=1; factorialnumber<=2*howlong-2; factorialnumber++){
factorial = factorial * howlong;
}
// now we need to create the pattern for the + and -
// so we use % that switches the sign everytime i increments by 1
if (howlong%2==1){
cos = cos + (double) (Math.pow(x, 2*howlong-2)/factorial);
}
else{
cos = cos - (double) (Math.pow(x, 2*howlong-2)/factorial);
}
}
return cos;
}
edit: I figured out my mistake as it was multiplying the factorial by how long instead of factorial number.
You have two bugs.
(Bug 1) Where you wrote
factorial = factorial * howlong;
it should have been
factorial = factorial * factorialnumber;
(Bug 2) You're not resetting your factorials on each iteration through the outer loop. So you need to move the line
double factorial =1;
down a couple of lines, so that it's inside the outer loop.
If you make those two changes, then the result of cos(Math.PI / 6, 10) is 0.8660254037844386 which seems correct to me.
The computation of your factorial was wrong.
Try it with this code:
public static double cos(double x, int n) {
// declaring cos and factorial
double cos = 0.0;
// this loop determines how long does the loop go so the answer is more
// accurate
for (long howlong = 1; howlong <= n; howlong++) {
// now we need to create the pattern for the + and -
// so we use % that switches the sign everytime i increments by 1
if (howlong % 2 == 1) {
cos = cos + Math.pow(x, 2 * howlong - 2) / factorial(2 * howlong - 2);
}
else {
cos = cos - Math.pow(x, 2 * howlong - 2) / factorial(2 * howlong - 2);
}
}
return cos;
}
public static long factorial(long n) {
long result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
Your calculation is not correct, please change to
double value = 1;
for (int factorialnumber = 1; factorialnumber <= 2 * howlong - 2; factorialnumber++) {
value = factorialnumber * value;
}
factorial = value;
System.out.println(value + " " + (2 * howlong - 2));
Related
Question:
A class SeriesSum is designed to calculate the sum of the following series:
Class name : SeriesSum
Data members/instance variables:
x : to store an integer number
n : to store number of terms
sum : double variable to store the sum of the series
Member functions:
SeriesSum(int xx, int nn) : constructor to assign x=xx and n=nn
double findfact(int m) to return the factorial of m using recursive
technique.
double findpower(int x, int y) : to return x raised to the power of y using
recursive technique.
void calculate( ) : to calculate the sum of the series by invoking
the recursive functions respectively
void display( ) : to display the sum of the series
(a) Specify the class SeriesSum, giving details of the constructor(int, int),
double findfact(int), double findpower(int, int), void calculate( ) and
void display( ).
Define the main( ) function to create an object and call the
functions accordingly to enable the task.
Code:
class SeriesSum
{
int x,n;
double sum;
SeriesSum(int xx,int nn)
{ x=xx;
n=nn;
sum=0.0;
}
double findfact(int a)
{ return (a<2)? 1:a*findfact(a-1);
}
double findpower(int a, int b)
{ return (b==0)? 1:a*findpower(a,b-1);
}
void calculate()
{ for(int i=2;i<=n;i+=2)
sum += findpower(x,i)/findfact(i-1);
}
void display()
{ System.out.println("sum="+ sum);
}
static void main()
{ SeriesSum obj = new SeriesSum(3,8);
obj.calculate();
obj.display();
}
}
MyProblem:
I am having problems in understanding that when i= any odd number (Taking an example such as 3 here)then it value that passes through findfact is (i-1)=2 then how am I getting the odd factorials such as 3!
Any help or guidance would be highly appreciated.
Optional:
If you can somehow explain the recursion taking place in the findpower and findfactorial,it would be of great help.
Take a closer look a the loop. i starts at 2 and is incremented by 2 every iteration, so it is never odd. It corresponds to the successive powers of x, each of which is divided by the factorial of i -1 (which IS odd).
As for the recursion in findfact, you just need to unwrap the first few calls by hand to see why it works :
findfact(a) = a * findfact(a -1)
= a * (a - 1) * findfact(a -2)
= a * (a - 1) * (a - 2) * findfact(a - 3)
...
= a * (a - 1) * (a - 2) * ... * 2 * findfact(1)
= a * (a - 1) * (a - 2) * ... * 2 * 1
= a!*
The same reasoning works with findpower.
As a side note, while it may be helpful for teaching purposes, recursion is a terrible idea for computing factorials or powers.
I'm not sure I understand your question correctly, but I try to help you the best I can.
I am having problems in understanding that when i= any odd number
In this code i never will be any odd number
for(int i=2;i<=n;i+=2)
i will be: 2 , 4 , 6 , 8 and so on because i+=2
The Recursion
The findfact() function in a more readable version:
double findfact(int a){
if(a < 2 ){
return 1;
} else {
return a * findfact(a - 1);
}
}
you can imagine it as a staircase, every call of findfact is a step:
We test: if a < 2 then return 1 else we call findfact() again with a-1 and multiply a with the result of findfact()
The same function without recursion:
double findfact(int a){
int sum = 1;
for(int i = a; i > 0; i--){
sum *= i;
}
return sum;
}
Same by the findpower function:
if b == 0 then return 1 else call findpower() with a, b-1 and multiply the return value of findpower() with a
So the last called findpower() will return 1 (b = 0)
The second last findpower() will return a * 1 (b = 1)
The third last findpower() will return a * a * 1 (b = 2)
so you can see findpower(a, 2) = a * a * 1 = a^2
Hope I could help you
Try to run below code, it will clear all your doubts (i have modified some access specifier and created main method)
public class SeriesSum
{
int x,n;
double sum;
SeriesSum(int xx,int nn)
{ x=xx;
n=nn;
sum=0.0;
}
double findfact(int a)
{ return (a<2)? 1:a*findfact(a-1);
}
double findpower(int a, int b)
{ return (b==0)? 1:a*findpower(a,b-1);
}
void calculate()
{
System.out.println("x ="+x);
System.out.println("n ="+n);
for(int i=2;i<=n;i+=2){
System.out.println(x+"^"+i+"/"+(i-1)+"!" +" = " +(findpower(x,i)+"/"+findfact(i-1)) );
//System.out.println(findpower(x,i)+"/"+findfact(i-1));
sum += findpower(x,i)/findfact(i-1);
}
}
void display()
{ System.out.println("sum="+ sum);
}
public static void main(String arg[])
{ SeriesSum obj = new SeriesSum(3,8);
obj.calculate();
obj.display();
}
}
// ----- output ----
x =3
n =8
3^2/1! = 9.0/1.0
3^4/3! = 81.0/6.0
3^6/5! = 729.0/120.0
3^8/7! = 6561.0/5040.0
sum=29.876785714285713
You can simplify the summation and get rid of power and factorial. Please notice:
The very first term is just x * x
If you know term item == x ** (2 * n) / (2 * n - 1)! the next one will be item * x * x / (2 * n) / (2 * n + 1).
Implementation:
private static double sum(double x, int count) {
double item = x * x; // First item
double result = item;
for (int i = 1; i <= count; ++i) {
// Next item from previous
item = item * x * x / (2 * i) / (2 * i +1);
result += item;
}
return result;
}
In the real world, you can notice that
sinh(x) = x/1! + x**3/3! + x**5/5! + ... + x**(2*n - 1) / (2*n - 1)! + ...
and your serie is nothing but
x * sinh(x) = x**2/1! + x**4 / 3! + ... + x**(2*n) / (2*n - 1)! + ...
So you can implement
private static double sum(double x) {
return x * (Math.exp(x) - Math.exp(-x)) / 2.0;
}
I got bored and decided to dive into remaking the square root function without referencing any of the Math.java functions. I have gotten to this point:
package sqrt;
public class SquareRoot {
public static void main(String[] args) {
System.out.println(sqrtOf(8));
}
public static double sqrtOf(double n){
double x = log(n,2);
return powerOf(2, x/2);
}
public static double log(double n, double base)
{
return (Math.log(n)/Math.log(base));
}
public static double powerOf(double x, double y) {
return powerOf(e(),y * log(x, e()));
}
public static int factorial(int n){
if(n <= 1){
return 1;
}else{
return n * factorial((n-1));
}
}
public static double e(){
return 1/factorial(1);
}
public static double e(int precision){
return 1/factorial(precision);
}
}
As you may very well see, I came to the point in my powerOf() function that infinitely recalls itself. I could replace that and use Math.exp(y * log(x, e()), so I dived into the Math source code to see how it handled my problem, resulting in a goose chase.
public static double exp(double a) {
return StrictMath.exp(a); // default impl. delegates to StrictMath
}
which leads to:
public static double exp(double x)
{
if (x != x)
return x;
if (x > EXP_LIMIT_H)
return Double.POSITIVE_INFINITY;
if (x < EXP_LIMIT_L)
return 0;
// Argument reduction.
double hi;
double lo;
int k;
double t = abs(x);
if (t > 0.5 * LN2)
{
if (t < 1.5 * LN2)
{
hi = t - LN2_H;
lo = LN2_L;
k = 1;
}
else
{
k = (int) (INV_LN2 * t + 0.5);
hi = t - k * LN2_H;
lo = k * LN2_L;
}
if (x < 0)
{
hi = -hi;
lo = -lo;
k = -k;
}
x = hi - lo;
}
else if (t < 1 / TWO_28)
return 1;
else
lo = hi = k = 0;
// Now x is in primary range.
t = x * x;
double c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
if (k == 0)
return 1 - (x * c / (c - 2) - x);
double y = 1 - (lo - x * c / (2 - c) - hi);
return scale(y, k);
}
Values that are referenced:
LN2 = 0.6931471805599453, // Long bits 0x3fe62e42fefa39efL.
LN2_H = 0.6931471803691238, // Long bits 0x3fe62e42fee00000L.
LN2_L = 1.9082149292705877e-10, // Long bits 0x3dea39ef35793c76L.
INV_LN2 = 1.4426950408889634, // Long bits 0x3ff71547652b82feL.
INV_LN2_H = 1.4426950216293335, // Long bits 0x3ff7154760000000L.
INV_LN2_L = 1.9259629911266175e-8; // Long bits 0x3e54ae0bf85ddf44L.
P1 = 0.16666666666666602, // Long bits 0x3fc555555555553eL.
P2 = -2.7777777777015593e-3, // Long bits 0xbf66c16c16bebd93L.
P3 = 6.613756321437934e-5, // Long bits 0x3f11566aaf25de2cL.
P4 = -1.6533902205465252e-6, // Long bits 0xbebbbd41c5d26bf1L.
P5 = 4.1381367970572385e-8, // Long bits 0x3e66376972bea4d0L.
TWO_28 = 0x10000000, // Long bits 0x41b0000000000000L
Here is where I'm starting to get lost. But I can make a few assumptions that so far the answer is starting to become estimated. I then find myself here:
private static double scale(double x, int n)
{
if (Configuration.DEBUG && abs(n) >= 2048)
throw new InternalError("Assertion failure");
if (x == 0 || x == Double.NEGATIVE_INFINITY
|| ! (x < Double.POSITIVE_INFINITY) || n == 0)
return x;
long bits = Double.doubleToLongBits(x);
int exp = (int) (bits >> 52) & 0x7ff;
if (exp == 0) // Subnormal x.
{
x *= TWO_54;
exp = ((int) (Double.doubleToLongBits(x) >> 52) & 0x7ff) - 54;
}
exp += n;
if (exp > 0x7fe) // Overflow.
return Double.POSITIVE_INFINITY * x;
if (exp > 0) // Normal.
return Double.longBitsToDouble((bits & 0x800fffffffffffffL)
| ((long) exp << 52));
if (exp <= -54)
return 0 * x; // Underflow.
exp += 54; // Subnormal result.
x = Double.longBitsToDouble((bits & 0x800fffffffffffffL)
| ((long) exp << 52));
return x * (1 / TWO_54);
}
TWO_54 = 0x40000000000000L
While I am, I would say, very understanding of math and programming, I hit the point to where I find myself at a Frankenstein monster mix of the two. I noticed the intrinsic switch to bits (which I have little to no experience with), and I was hoping someone could explain to me the processes that are occurring "under the hood" so to speak. Specifically where I got lost is from "Now x is in primary range" in the exp() method on wards and what the values that are being referenced really represent. I'm was asking for someone to help me understand not only the methods themselves, but also how they arrive to the answer. Feel free to go as in depth as needed.
edit:
if someone could maybe make this tag: "strictMath" that would be great. I believe that its size and for the Math library deriving from it justifies its existence.
To the exponential function:
What happens is that
exp(x) = 2^k * exp(x-k*log(2))
is exploited for positive x. Some magic is used to get more consistent results for large x where the reduction x-k*log(2) will introduce cancellation errors.
On the reduced x a rational approximation with minimized maximal error over the interval 0.5..1.5 is used, see Pade approximations and similar. This is based on the symmetric formula
exp(x) = exp(x/2)/exp(-x/2) = (c(x²)+x)/(c(x²)-x)
(note that the c in the code is x+c(x)-2). When using Taylor series, approximations for c(x*x)=x*coth(x/2) are based on
c(u)=2 + 1/6*u - 1/360*u^2 + 1/15120*u^3 - 1/604800*u^4 + 1/23950080*u^5 - 691/653837184000*u^6
The scale(x,n) function implements the multiplication x*2^n by directly manipulating the exponent in the bit assembly of the double floating point format.
Computing square roots
To compute square roots it would be more advantageous to compute them directly. First reduce the interval of approximation arguments via
sqrt(x)=2^k*sqrt(x/4^k)
which can again be done efficiently by directly manipulating the bit format of double.
After x is reduced to the interval 0.5..2.0 one can then employ formulas of the form
u = (x-1)/(x+1)
y = (c(u*u)+u) / (c(u*u)-u)
based on
sqrt(x)=sqrt(1+u)/sqrt(1-u)
and
c(v) = 1+sqrt(1-v) = 2 - 1/2*v - 1/8*v^2 - 1/16*v^3 - 5/128*v^4 - 7/256*v^5 - 21/1024*v^6 - 33/2048*v^7 - ...
In a program without bit manipulations this could look like
double my_sqrt(double x) {
double c,u,v,y,scale=1;
int k=0;
if(x<0) return NaN;
while(x>2 ) { x/=4; scale *=2; k++; }
while(x<0.5) { x*=4; scale /=2; k--; }
// rational approximation of sqrt
u = (x-1)/(x+1);
v = u*u;
c = 2 - v/2*(1 + v/4*(1 + v/2));
y = 1 + 2*u/(c-u); // = (c+u)/(c-u);
// one Halley iteration
y = y*(1+8*x/(3*(3*y*y+x))) // = y*(y*y+3*x)/(3*y*y+x)
// reconstruct original scale
return y*scale;
}
One could replace the Halley step with two Newton steps, or
with a better uniform approximation in c one could replace the Halley step with one Newton step, or ...
Note: Updated on 06/17/2015. Of course this is possible. See the solution below.
Even if anyone copies and pastes this code, you still have a lot of cleanup to do. Also note that you will have problems inside the critical strip from Re(s) = 0 to Re(s) = 1 :). But this is a good start.
import java.util.Scanner;
public class NewTest{
public static void main(String[] args) {
RiemannZetaMain func = new RiemannZetaMain();
double s = 0;
double start, stop, totalTime;
Scanner scan = new Scanner(System.in);
System.out.print("Enter the value of s inside the Riemann Zeta Function: ");
try {
s = scan.nextDouble();
}
catch (Exception e) {
System.out.println("You must enter a positive integer greater than 1.");
}
start = System.currentTimeMillis();
if (s <= 0)
System.out.println("Value for the Zeta Function = " + riemannFuncForm(s));
else if (s == 1)
System.out.println("The zeta funxtion is undefined for Re(s) = 1.");
else if(s >= 2)
System.out.println("Value for the Zeta Function = " + getStandardSum(s));
else
System.out.println("Value for the Zeta Function = " + getNewSum(s));
stop = System.currentTimeMillis();
totalTime = (double) (stop-start) / 1000.0;
System.out.println("Total time taken is " + totalTime + " seconds.");
}
// Standard form the the Zeta function.
public static double standardZeta(double s) {
int n = 1;
double currentSum = 0;
double relativeError = 1;
double error = 0.000001;
double remainder;
while (relativeError > error) {
currentSum = Math.pow(n, -s) + currentSum;
remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
relativeError = remainder / currentSum;
n++;
}
System.out.println("The number of terms summed was " + n + ".");
return currentSum;
}
public static double getStandardSum(double s){
return standardZeta(s);
}
//New Form
// zeta(s) = 2^(-1+2 s)/((-2+2^s) Gamma(1+s)) integral_0^infinity t^s sech^2(t) dt for Re(s)>-1
public static double Integrate(double start, double end) {
double currentIntegralValue = 0;
double dx = 0.0001d; // The size of delta x in the approximation
double x = start; // A = starting point of integration, B = ending point of integration.
// Ending conditions for the while loop
// Condition #1: The value of b - x(i) is less than delta(x).
// This would throw an out of bounds exception.
// Condition #2: The value of b - x(i) is greater than 0 (Since you start at A and split the integral
// up into "infinitesimally small" chunks up until you reach delta(x)*n.
while (Math.abs(end - x) >= dx && (end - x) > 0) {
currentIntegralValue += function(x) * dx; // Use the (Riemann) rectangle sums at xi to compute width * height
x += dx; // Add these sums together
}
return currentIntegralValue;
}
private static double function(double s) {
double sech = 1 / Math.cosh(s); // Hyperbolic cosecant
double squared = Math.pow(sech, 2);
return ((Math.pow(s, 0.5)) * squared);
}
public static double getNewSum(double s){
double constant = Math.pow(2, (2*s)-1) / (((Math.pow(2, s)) -2)*(gamma(1+s)));
return constant*Integrate(0, 1000);
}
// Gamma Function - Lanczos approximation
public static double gamma(double s){
double[] p = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
771.32342877765313, -176.61502916214059, 12.507343278686905,
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
int g = 7;
if(s < 0.5) return Math.PI / (Math.sin(Math.PI * s)*gamma(1-s));
s -= 1;
double a = p[0];
double t = s+g+0.5;
for(int i = 1; i < p.length; i++){
a += p[i]/(s+i);
}
return Math.sqrt(2*Math.PI)*Math.pow(t, s+0.5)*Math.exp(-t)*a;
}
//Binomial Co-efficient - NOT CURRENTLY USING
/*
public static double binomial(int n, int k)
{
if (k>n-k)
k=n-k;
long b=1;
for (int i=1, m=n; i<=k; i++, m--)
b=b*m/i;
return b;
} */
// Riemann's Functional Equation
// Tried this initially and utterly failed.
public static double riemannFuncForm(double s) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
double nextTerm = Math.pow(2, (1-s))*Math.pow(Math.PI, (1-s)-1)*(Math.sin((Math.PI*(1-s))/2))*gamma(1-(1-s));
double error = Math.abs(term - nextTerm);
if(s == 1.0)
return 0;
else
return Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)*standardZeta(1-s);
}
}
Ok well we've figured out that for this particular function, since this form of it isn't actually a infinite series, we cannot approximate using recursion. However the infinite sum of the Riemann Zeta series (1\(n^s) where n = 1 to infinity) could be solved through this method.
Additionally this method could be used to find any infinite series' sum, product, or limit.
If you execute the code your currently have, you'll get infinite recursion as 1-(1-s) = s (e.g. 1-s = t, 1-t = s so you'll just switch back and forth between two values of s infinitely).
Below I talk about the sum of series. It appears you are calculating the product of the series instead. The concepts below should work for either.
Besides this, the Riemann Zeta Function is an infinite series. This means that it only has a limit, and will never reach a true sum (in finite time) and so you cannot get an exact answer through recursion.
However, if you introduce a "threshold" factor, you can get an approximation that is as good as you like. The sum will increase/decrease as each term is added. Once the sum stabilizes, you can quit out of recursion and return your approximate sum. "Stabilized" is defined using your threshold factor. Once the sum varies by an amount less than this threshold factor (which you have defined), your sum has stabilized.
A smaller threshold leads to a better approximation, but also longer computation time.
(Note: this method only works if your series converges, if it has a chance of not converging, you might also want to build in a maxSteps variable to cease execution if the series hasn't converged to your satisfaction after maxSteps steps of recursion.)
Here's an example implementation, note that you'll have to play with threshold and maxSteps to determine appropriate values:
/* Riemann's Functional Equation
* threshold - if two terms differ by less than this absolute amount, return
* currSteps/maxSteps - if currSteps becomes maxSteps, give up on convergence and return
* currVal - the current product, used to determine threshold case (start at 1)
*/
public static double riemannFuncForm(double s, double threshold, int currSteps, int maxSteps, double currVal) {
double nextVal = currVal*(Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)); //currVal*term
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else if (Math.abs(currVal-nextVal) < threshold) //When a term will change the current answer by less than threshold
return nextVal; //Could also do currVal here (shouldn't matter much as they differ by < threshold)
else if (currSteps == maxSteps)//When you've taken the max allowed steps
return nextVal; //You might want to print something here so you know you didn't converge
else //Otherwise just keep recursing
return riemannFuncForm(1-s, threshold, ++currSteps, maxSteps, nextVal);
}
}
This is not possible.
The functional form of the Riemann Zeta Function is --
zeta(s) = 2^s pi^(-1+s) Gamma(1-s) sin((pi s)/2) zeta(1-s)
This is different from the standard equation in which an infinite sum is measured from 1/k^s for all k = 1 to k = infinity. It is possible to write this as something similar to --
// Standard form the the Zeta function.
public static double standardZeta(double s) {
int n = 1;
double currentSum = 0;
double relativeError = 1;
double error = 0.000001;
double remainder;
while (relativeError > error) {
currentSum = Math.pow(n, -s) + currentSum;
remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
relativeError = remainder / currentSum;
n++;
}
System.out.println("The number of terms summed was " + n + ".");
return currentSum;
}
The same logic doesn't apply to the functional equation (it isn't a direct sum, it is a mathematical relationship). This would require a rather clever way of designing a program to calculate negative values of Zeta(s)!
The literal interpretation of this Java code is ---
// Riemann's Functional Equation
public static double riemannFuncForm(double s) {
double currentVal = (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else
System.out.println("Value of next value is " + nextVal(1-s));
return currentVal;//*nextVal(1-s);
}
public static double nextVal(double s)
{
return (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
}
public static double getRiemannSum(double s) {
return riemannFuncForm(s);
}
Testing on three or four values shows that this doesn't work. If you write something similar to --
// Riemann's Functional Equation
public static double riemannFuncForm(double s) {
double currentVal = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s); //currVal*term
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else //Otherwise just keep recursing
return currentVal * nextVal(1-s);
}
public static double nextVal(double s)
{
return (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
}
I was misinterpretation how to do this through mathematics. I will have to use a different approximation of the zeta function for values less than 2.
I think I need to use a different form of the zeta function. When I run the entire program ---
import java.util.Scanner;
public class Test4{
public static void main(String[] args) {
RiemannZetaMain func = new RiemannZetaMain();
double s = 0;
double start, stop, totalTime;
Scanner scan = new Scanner(System.in);
System.out.print("Enter the value of s inside the Riemann Zeta Function: ");
try {
s = scan.nextDouble();
}
catch (Exception e) {
System.out.println("You must enter a positive integer greater than 1.");
}
start = System.currentTimeMillis();
if(s >= 2)
System.out.println("Value for the Zeta Function = " + getStandardSum(s));
else
System.out.println("Value for the Zeta Function = " + getRiemannSum(s));
stop = System.currentTimeMillis();
totalTime = (double) (stop-start) / 1000.0;
System.out.println("Total time taken is " + totalTime + " seconds.");
}
// Standard form the the Zeta function.
public static double standardZeta(double s) {
int n = 1;
double currentSum = 0;
double relativeError = 1;
double error = 0.000001;
double remainder;
while (relativeError > error) {
currentSum = Math.pow(n, -s) + currentSum;
remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
relativeError = remainder / currentSum;
n++;
}
System.out.println("The number of terms summed was " + n + ".");
return currentSum;
}
public static double getStandardSum(double s){
return standardZeta(s);
}
// Riemann's Functional Equation
public static double riemannFuncForm(double s, double threshold, double currSteps, int maxSteps) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
//double nextTerm = Math.pow(2, (1-s))*Math.pow(Math.PI, (1-s)-1)*(Math.sin((Math.PI*(1-s))/2))*gamma(1-(1-s));
//double error = Math.abs(term - nextTerm);
if(s == 1.0)
return 0;
else if (s == 0.0)
return -0.5;
else if (term < threshold) {//The recursion will stop once the term is less than the threshold
System.out.println("The number of steps is " + currSteps);
return term;
}
else if (currSteps == maxSteps) {//The recursion will stop if you meet the max steps
System.out.println("The series did not converge.");
return term;
}
else //Otherwise just keep recursing
return term*riemannFuncForm(1-s, threshold, ++currSteps, maxSteps);
}
public static double getRiemannSum(double s) {
double threshold = 0.00001;
double currSteps = 1;
int maxSteps = 1000;
return riemannFuncForm(s, threshold, currSteps, maxSteps);
}
// Gamma Function - Lanczos approximation
public static double gamma(double s){
double[] p = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
771.32342877765313, -176.61502916214059, 12.507343278686905,
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
int g = 7;
if(s < 0.5) return Math.PI / (Math.sin(Math.PI * s)*gamma(1-s));
s -= 1;
double a = p[0];
double t = s+g+0.5;
for(int i = 1; i < p.length; i++){
a += p[i]/(s+i);
}
return Math.sqrt(2*Math.PI)*Math.pow(t, s+0.5)*Math.exp(-t)*a;
}
//Binomial Co-efficient
public static double binomial(int n, int k)
{
if (k>n-k)
k=n-k;
long b=1;
for (int i=1, m=n; i<=k; i++, m--)
b=b*m/i;
return b;
}
}
I notice that plugging in zeta(-1) returns -
Enter the value of s inside the Riemann Zeta Function: -1
The number of steps is 1.0
Value for the Zeta Function = -0.0506605918211689
Total time taken is 0.0 seconds.
I knew that this value was -1/12. I checked some other values with wolfram alpha and observed that --
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
Returns the correct value. It is just that I am multiplying this value every time by zeta(1-s). In the case of Zeta(1/2), this will always multiply the result by 0.99999999.
Enter the value of s inside the Riemann Zeta Function: 0.5
The series did not converge.
Value for the Zeta Function = 0.999999999999889
Total time taken is 0.006 seconds.
I am going to see if I can replace the part for --
else if (term < threshold) {//The recursion will stop once the term is less than the threshold
System.out.println("The number of steps is " + currSteps);
return term;
}
This difference is the error between two terms in the summation. I may not be thinking about this correctly, it is 1:16am right now. Let me see if I can think better tomorrow ....
I know Math.sin() can work but I need to implement it myself using factorial(int) I have a factorial method already below are my sin method but I can't get the same result as Math.sin():
public static double factorial(double n) {
if (n <= 1) // base case
return 1;
else
return n * factorial(n - 1);
}
public static double sin(int n) {
double sum = 0.0;
for (int i = 1; i <= n; i++) {
if (i % 2 == 0) {
sum += Math.pow(1, i) / factorial(2 * i + 1);
} else {
sum += Math.pow(-1, i) / factorial(2 * i + 1);
}
}
return sum;
}
You should use the Taylor series. A great tutorial here
I can see that you've tried but your sin method is incorrect
public static sin(int n) {
// angle to radians
double rad = n*1./180.*Math.PI;
// the first element of the taylor series
double sum = rad;
// add them up until a certain precision (eg. 10)
for (int i = 1; i <= PRECISION; i++) {
if (i % 2 == 0)
sum += Math.pow(rad, 2*i+1) / factorial(2 * i + 1);
else
sum -= Math.pow(rad, 2*i+1) / factorial(2 * i + 1);
}
return sum;
}
A working example of calculating the sin function. Sorry I've jotted it down in C++, but hope you get the picture. It's not that different :)
Your formula is wrong and you are getting a rough result of sin(1) and all you're doing by changing n is changing the accuracy of this calculation. You should look the formula up in Wikipedia and there you'll see that your n is in the wrong place and shouldn't be used as the limit of the for loop but rather in the numerator of the fraction, in the Math.pow(...) method. Check out Taylor Series
It looks like you are trying to use the taylor series expansion for sin, but have not included the term for x. Therefore, your method will always attempt to approximate sin(1) regardless of argument.
The method parameter only controls accuracy. In a good implementation, a reasonable value for that parameter is auto-detected, preventing the caller from passing to low a value, which can result in highly inaccurate results for large x. Moreover, to assist fast convergence (and prevent unnecessary loss of significance) of the series, implementations usually use that sin(x + k * 2 * PI) = sin(x) to first move x into the range [-PI, PI].
Also, your method is not very efficient, due to the repeated evaluations of factorials. (To evaluate factorial(5) you compute factorial(3), which you have already computed in the previous iteration of the for-loop).
Finally, note that your factorial implementation accepts an argument of type double, but is only correct for integers, and your sin method should probably receive the angle as double.
Sin (x) can be represented as Taylor series:
Sin (x) = (x/1!) – (x3/3!) + (x5/5!) - (x7/7!) + …
So you can write your code like this:
public static double getSine(double x) {
double result = 0;
for (int i = 0, j = 1, k = 1; i < 100; i++, j = j + 2, k = k * -1) {
result = result + ((Math.pow(x, j) / factorial (j)) * k);
}
return result;
}
Here we have run our loop only 100 times. If you want to run more than that you need to change your base equation (otherwise infinity value will occur).
I have learned a very good trick from the book “How to solve it by computer” by R.G.Dromey. He explain it like this way:
(x3/3! ) = (x X x X x)/(3 X 2 X 1) = (x2/(3 X 2)) X (x1/1!) i = 3
(x5/5! ) = (x X x X x X x X x)/(5 X 4 X 3 X 2 X 1) = (x2/(5 X 4)) X (x3/3!) i = 5
(x7/7! ) = (x X x X x X x X x X x X x)/(7 X 6 X 5 X 4 X 3 X 2 X 1) = (x2/(7 X 6)) X (x5/5!) i = 7
So the terms (x2/(3 X 2)) , (x2/(5 X 4)), (x2/(7 X 6)) can be expressed as x2/(i X (i - 1)) for i = 3,5,7,…
Therefore to generate consecutive terms of the sine series we can write:
current ith term = (x2 / ( i X (i - 1)) ) X (previous term)
The code is following:
public static double getSine(double x) {
double result = 0;
double term = x;
result = x;
for (int i = 3, j = -1; i < 100000000; i = i + 2, j = j * -1) {
term = x * x * term / (i * (i - 1));
result = result + term * j;
}
return result;
}
Note that j variable used to alternate the sign of the term .
I'm trying to write a function in Java that calculates the n-th root of a number. I'm using Newton's method for this. However, the user should be able to specify how many digits of precision they want. This is the part with which I'm having trouble, as my answer is often not entirely correct. The relevant code is here: http://pastebin.com/d3rdpLW8. How could I fix this code so that it always gives the answer to at least p digits of precision? (without doing more work than is necessary)
import java.util.Random;
public final class Compute {
private Compute() {
}
public static void main(String[] args) {
Random rand = new Random(1230);
for (int i = 0; i < 500000; i++) {
double k = rand.nextDouble()/100;
int n = (int)(rand.nextDouble() * 20) + 1;
int p = (int)(rand.nextDouble() * 10) + 1;
double math = n == 0 ? 1d : Math.pow(k, 1d / n);
double compute = Compute.root(n, k, p);
if(!String.format("%."+p+"f", math).equals(String.format("%."+p+"f", compute))) {
System.out.println(String.format("%."+p+"f", math));
System.out.println(String.format("%."+p+"f", compute));
System.out.println(math + " " + compute + " " + p);
}
}
}
/**
* Returns the n-th root of a positive double k, accurate to p decimal
* digits.
*
* #param n
* the degree of the root.
* #param k
* the number to be rooted.
* #param p
* the decimal digit precision.
* #return the n-th root of k
*/
public static double root(int n, double k, int p) {
double epsilon = pow(0.1, p+2);
double approx = estimate_root(n, k);
double approx_prev;
do {
approx_prev = approx;
// f(x) / f'(x) = (x^n - k) / (n * x^(n-1)) = (x - k/x^(n-1)) / n
approx -= (approx - k / pow(approx, n-1)) / n;
} while (abs(approx - approx_prev) > epsilon);
return approx;
}
private static double pow(double x, int y) {
if (y == 0)
return 1d;
if (y == 1)
return x;
double k = pow(x * x, y >> 1);
return (y & 1) == 0 ? k : k * x;
}
private static double abs(double x) {
return Double.longBitsToDouble((Double.doubleToLongBits(x) << 1) >>> 1);
}
private static double estimate_root(int n, double k) {
// Extract the exponent from k.
long exp = (Double.doubleToLongBits(k) & 0x7ff0000000000000L);
// Format the exponent properly.
int D = (int) ((exp >> 52) - 1023);
// Calculate and return 2^(D/n).
return Double.longBitsToDouble((D / n + 1023L) << 52);
}
}
Just iterate until the update is less than say, 0.0001, if you want a precision of 4 decimals.
That is, set your epsilon to Math.pow(10, -n) if you want n digits of precision.
Let's recall what the error analysis of Newton's method says. Basically, it gives us an error for the nth iteration as a function of the error of the n-1 th iteration.
So, how can we tell if the error is less than k? We can't, unless we know the error at e(0). And if we knew the error at e(0), we would just use that to find the correct answer.
What you can do is say "e(0) <= m". You can then find n such that e(n) <= k for your desired k. However, this requires knowing the maximal value of f'' in your radius, which is (in general) just as hard a problem as finding the x intercept.
What you're checking is if the error changes by less than k, which is a perfectly acceptable way to do it. But it's not checking if the error is less than k. As Axel and others have noted, there are many other root-approximation algorithms, some of which will yield easier error analysis, and if you really want this, you should use one of those.
You have a bug in your code. Your pow() method's last line should read
return (y & 1) == 1 ? k : k * x;
rather than
return (y & 1) == 0 ? k : k * x;