Riemann Zeta function in C for negative's odd reals - c

I'm trying to code the Riemann Zeta function in C but I'm having quite issues with the negative odds one. Since Even negatives are 0 by definition. Only for Real numbers the function, not complex. So 0..1 it's undefined. I know it's some math error I'm doing, but I started today to read about this function and I'm trying to learn.
https://en.wikipedia.org/wiki/Riemann_zeta_function
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double zeta(double s, long long int n)
{
double p=0.0;
if(s<0 && fmod(s,2)==0)
{
return p;
}
if(s==0) { return -0.5;}
if(s>0 && s<=1)
{
puts("Undefined. ");
exit(-1);
}
long long int i;
for(i=n; i>0; i--)
{
p+=pow(i,-s);
}
return p;
}
int main()
{
double s;
puts("Enter real number to Zeta function: ");
scanf("%lf",&s);
printf("\n%.15lf",zeta(s,1000000));
return 0;
}
It's just a sketch... Nothing professional here!
example: zeta(-5) = -0.003968253968253
it's giving 1.036927755143338...
I'm only having issues with NEGATIVE REAL ones...
I'm on Windows 10, Codeblocks with GCC.
The code was update with the #NPE contributions but still not working for negative real odds...

I did not participate in comments, sorry.
following the definition of the zeta-function the simple way of coding is (I just changed s to -s from your code, and added the 'level of convergence n' as a parameter)
double zeta_simple(double s, long long int n)
{
double p=0.0;
long long int i;
for(i=1; i<=n; i++)
{
p+=pow(i,-s);
}
return p;
}
However the problem is that you start adding the "big" numbers before the "small" and soon you will hit underflow operation. So what you want to do is
double zeta(double s, long long int n)
{
double p=0.0;
long long int i;
for(i=n; i>0; i--)
{
p+=pow(i,-s);
}
return p;
}
you can test convergence with s=2 which converges to PI^2/6.0 and s=4 which converges to PI^4/90.0
#define PI 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679L
int main()
{
long long int n;
for (long long int n=10; n<=100000000; n*=10)
{
printf("%28.16f\t %28.16f\n", zeta(4.0, n), zeta2(4.0, n));
}
printf("%s=%20.16f\n\n","PI^4/90", PI*PI*PI*PI/90.0);
for (long long int n=10; n<=10000000000; n*=10)
{
printf("%28.16f\t %28.16f\n", zeta(2.0, n), zeta2(2.0, n));
}
printf("%s=%20.16f\n","PI^2/6 ", PI*PI/6.0);
}
you get
1.0820365834937564 1.0820365834937566
1.0823229053444732 1.0823229053444725
1.0823232333783044 1.0823232333783073
1.0823232337108049 1.0823232337108359
1.0823232337111379 1.0823232337109849
1.0823232337111381 1.0823232337109849
1.0823232337111381 1.0823232337109849
1.0823232337111381 1.0823232337109849
PI^4/90= 1.0823232337111379
1.5497677311665408 1.5497677311665408
1.6349839001848929 1.6349839001848925
1.6439345666815597 1.6439345666815606
1.6448340718480596 1.6448340718480665
1.6449240668982261 1.6449240668982523
1.6449330668487265 1.6449330668487985
1.6449339668482315 1.6449339668477756
1.6449340568482265 1.6449340573291047
1.6449340658482263 1.6449340600880324
1.6449340667482264 1.6449340600880324
PI^2/6 = 1.6449340668482264
see how the convergence of zeta_simple stops after a while... For convergence to continue you have to use zeta
You can also see that for 10000000000 operations (hence the use of long long int) you only get a precision on 9 digits for s=2. And as s increase so does the rate of convergence.
Therefore for small s to be efficient people use accelerated convergence formulae.
If you want to dig further I recommend you look at https://math.stackexchange.com/questions/183680/modern-formula-for-calculating-riemann-zeta-function
Also wat is really interesting is when you start poking around with s complex

Related

Can you please spot the error I made in C implementation of the Karatsuba algorithm

I need to implement the karatsuba algortihm into a c code for my homework and I did my research and came up with the following code:
long int karatsuba(long int x,long int y)
{
if((x<10)||(y<10)) \\if the numbers have 1 digit, I just multiply them
return x*y;
else
{
long int a, b, c, d, ac, bd, z;
int n=uzunluk(x);
a=floor(x/ust(10, ceil(n/2)));
b=x%ust(10, ceil(n/2));;
c=floor(y/ust(10, ceil(n/2)));
d=y%ust(10, ceil(n/2));;
ac=a*c;
bd=b*d;
z=(a+b)*(c+d)-ac-bd;
long int res=ust(10, 2*ceil(n/2))*ac+ust(10, ceil(n/2))*z+bd;
return res;
}
}
int main(void)
{
printf("%ld", karatsuba(837487, 368498));
return 0;
}
ust(x, n) is the function to get the power of number x:
long int ust(long x, long n)
{
long int res=1;
int i;
for(i=0; i<n; i++)
{
res*=x;
}
return res;
}
And the uzunluk(x) gets the number of digits in the given input:
int uzunluk(long int x)
{
int lx;
while(x>0)
{
x/=10;
lx+=1;
}
return lx;
}
the problem is this code prints nothing :D
I would be glad if someone could spot the mistake I made.
So it comes out the problem was 7 digits numbers' multiplication does not result proper under the long integer identification. As I changed it to long long int, it started working properly. Thank you all for your help

Factorial function only counts to 12

This factorial function starts giving wrong results with 13 and above. I have no idea why.
#include <stdio.h>
int fatorial (int p);
int main() {
int x = 13;
int test = fatorial(x);
printf("%d", test);
}
int fatorial (int p) {
if (p <= 0)
return 1;
else
return p*fatorial(p-1);
}
for x = 0, 1, 2 ...12 it prints the right result, but for 13! it prints 1932053504 which is not correct.
For x=20 it prints -210213273 for example.
I know that this is not the best way to do a factorial. Its my homework tho, it HAS to be this way.
If you try this you will get the maximum value that int can hold:
#include <stdio.h>
#include <limits.h>
int main(void)
{
printf("%d\n", INT_MAX);
}
Your code causes overflow.
You could get a few more numbers if you use a bigger type, but not by very much. You could use this:
unsigned long long fatorial (unsigned long long p) {
if (p <= 0)
return 1;
else
return p*fatorial(p-1);
}
It won't get you far though. If you want bigger than that you need to find a library for bigger integers or create some custom solution. One such library is https://gmplib.org/ but that is likely out of scope for your homework.
And btw, a condition like p <= 0 is not good. It indicates that the factorial of a negative number is always one, which is false.
It is because after 12, the result of factorial of any number exceeds the size of int.
you can try the following code:
#include<stdio.h>
int main()
{
int a[100],n,counter,temp,i;
a[0]=1;
counter=0;
printf("Enter the number: ");
scanf("%d",&n);
for(; n>=2; n--)
{
temp=0;
for(i=0; i<=counter; i++)
{
temp=(a[i]*n)+temp;
a[i]=temp%10;
temp=temp/10;
}
while(temp>0)
{
a[++counter]=temp%10;
temp=temp/10;
}
}
for(i=counter; i>=0; i--)
printf("%d",a[i]);
return 0;
}
The result of the function is too big. I think big int would work better for your purposes. Big int allows you to have bigger numbers. Also, this is what I would do.
int x = the number you want to factorialize
int ans = 1;
(Then instead of all of those functions)
for(var i = x; i > 0; i--) {
ans = ans*i;
}
System.out.println(ans);
Javascript link: https://jsfiddle.net/8gxyj913/
I need to get to 100!
100! is about 9.332622e+157. Simply using standard integer types is insufficient. 32-bit int is good to 12!. With 64-bit integer math, code could get to about 21!
Could use floating point math and give up precision.
Instead consider a string approach.

Time limit exceeded error on spoj.. How can i improve my solution?

We are given an array a[1..N]. For each element a[i] in the array, we note down the sum of all the elements which are smaller and occur before the present element. I need to calculate the total sum for every element in the array.
Constraints:
1<=N<=10^5
All elements will be between 0 and 10^6.
Here is the link to my question: http://www.spoj.com/problems/DCEPC206/. I'm using the approach shown below, but I'm getting TIME LIMIT EXCEEDED error on SPOJ. How can I improve my solution?
include
int main()
{
long n,a[100000],i,j,sum;
printf("enter the number of elements");
scanf("%ld",&n);
printf("enter the elements of the array");
for(i=0;i<n;i++)
scanf("%ld",&a[i]);
sum=0;
for(i=1;i<n;i++)
for(j=i-1;j>=0;j--)
if(a[i]>a[j])
sum+=a[j];
printf("\n%ld",sum);
return 0;
}
Yours is a trivial implementation which takes time of the order of O(n^2) but for the solution to get accepted you have to use Divide and Conquer as you do in Merge Sort which takes only O(NLogN) time compared to simpler sorting algorithms like Bubble Sort,etc.
For this you simply can change the Mergesort implementation a little bit simply by adding 2-3 lines of code in it. For understanding this better go through question of counting inversions in an array.(http://www.geeksforgeeks.org/counting-inversions/) Then you will realize you simply have to consider pairs opposite in nature to inversion and add all the smaller elements of all such pairs . For example - in an array 1,4,2,5 consider 4,2 is inversion but we have to consider pairs like 2,5 and 1,2 to get the solution. In every such pair keep adding the left no. ( Think hard about how it is doing our job !! )
For your reference go thoroughly through this merge sort code in which i have small changes to get a correct accepted solution.(sum variable stores the resultant value)
#include <stdio.h>
#include <stdlib.h>
long long int sum;
void merge(long long int c[],long long int arr[],long long int start,long long int middle,long long int end)
{
long long int i=0,j=start,k=middle;
while((j<middle)&&(k<end))
{
if(arr[j]<arr[k])
{
sum=sum+((end-k)*arr[j]);
c[i]=arr[j];
i++;j++;
}
else
{
c[i]=arr[k];
i++;k++;
}
}
while(j<middle)
{
c[i]=arr[j];
i++;
j++;
}
while(k<end)
{
c[i]=arr[k];
i++;
k++;
}
}
void msort(long long int arr[],long long int start,long long int end)
{
long long int middle=(start+end)/2;
if((end-start)==1)
{ return ;
}
msort(arr,start,middle);
msort(arr,middle,end);
long long int *c;
c=(long long int*)malloc(sizeof(long long int)*(end-start));
merge(c,arr,start,middle,end);
long long int i,j=0;
for(i=start;i<end;i++)
{
arr[i]=c[j];
j++;
}
}
void swap (long long int x[],long long int m,long long int n)
{
long long int t= x[m];
x[m]=x[n];
x[n]=t;
}
int main()
{
int t,i;
long long int n,*arr,j;
scanf("%d",&t);
for(i=0;i<t;i++)
{
scanf("%lld",&n);
arr = ( long long int * ) malloc ( sizeof(long long int) * n + 10);
for(j=0;j<n;j++)
{
scanf("%lld",&arr[j]);
}
sum=0;
msort(arr,0,n);
// for(j=0;j<n;j++)
// printf("%lld ",arr[j]);
printf("%lld\n",sum);
}
return 0;
}

How to fix SIGSEGV? (Error while dealing with large values upto 1000000 in Fibonacci Series)

Tried to develop a code that quickly finds Fibonacci values.
But the problem is I get SIGSEGV error when input is of order 1000000.
Also from other questions around here I came to know that it may be because of stack memory that exceeds limit during runtime. And I guess that is the case here.
#include<stdio.h>
unsigned long long int a[1000001] = {0};
unsigned long long int fib(int n)
{
unsigned long long int y;
if(n==1 || n==0)
return n;
if (a[n] != 0)
return a[n];
else
{
y=fib(n-1)+fib(n-2);
a[n] = y;
}
return y;
}
main()
{
int N;
unsigned long long int ans;
a[0] = 1;
a[1] = 1;
scanf(" %d",&N);
ans = fib(N+1);
printf("%llu",ans);
}
How do I fix this code for input value of 1000000?
Here's a better approach (which can still be significantly improved) that will calculate Fibonacci numbers for you:
unsigned long long Fibonacci(int n)
{
unsigned long long last[2] = { 0, 1 }; // the start of our sequence
if(n == 0)
return 0;
for(int i = 2; i <= n; i++)
last[i % 2] = last[0] + last[1];
return last[n % 2];
}
However, you are not going to be able to calculate the millionth Fibonacci number with it, because that number is much, much, much, much larger than the largest number that can fit in an unsigned long long.
Instead of using the stack, use your own variables to track state. Essentially, do the function calls and returns with your own code.
The best way really is just to switch the algorithm entirely to one that's efficient. For example, to calculate fib(6), your code calculates fib(4) twice, once when fib(5) asks and once when fib(6) asks.

How to create a datatype to hold 200+ digit long numbers in C?

OK,so I am trying to solve this problem: http://www.spoj.pl/problems/FCTRL2/
And using what I know about c, I have come up with this code:
#include <stdio.h>
#include <conio.h>
long double factorial(int);
int main()
{
long double num[100], fact[100];
int i = 0, ex;
scanf("%d", &ex);
for ( i = 0; i < ex; i++ )
{
scanf("%lf", &num[i]);
}
i = 0;
printf("\n");
for (i = 0; i < ex; i++ )
{
fact[i] = factorial(num[i]);
printf("%.0lf\n", fact[i]);
}
getch();
return 0;
}
long double factorial(int num)
{
long double onum, fact;
int i;
fact = 1;
onum = num;
for ( i = 1; i < onum; i++ )
{
fact = fact * num;
num--;
}
return fact;
}
The problem is that long double is not long enough to hold values as long as 100! So, how can I create a datatype that can hold this large value?
For this particular problem, GMP is indeed an overkill.
In fact, even the struct presented by Carl Norum, while useful and more general, contains more than what you will need. In particular, since all factorials are positive integers you don't need to worry about the sign.
Also, it's not necessary to implement addition, subtraction, or even general multiplication. You only need to worry about multiplying one of these "bignums" by an integer, which isn't too hard.
Here's a stub for the multiplication operation
void multiply( mybignum bn, int factor ) {
// for each of the digits in 'bn'
// multiplies 'factor' by the particular digit
// adds the previous remainder and stores
// the new carry value
}
There is no native data type that can hold numbers that large. Check out the GNU Multiple Precision Arithmetic Library.
GMP might be a little overkill for your particular problem, but it will get the job done. You could also write your own little arbitrary precision library to do it.
Edit - an example bignum type:
struct mybignum
{
int length;
int sign;
int digit[200];
};
You can just implement the grade-school algorithms for addition, subtraction, multiplication, etc. using that structure, and presto - 200-digit number support.

Resources