3
\$\begingroup\$

The problem is that I have executed the program for the last hour and it hasn't returned a value till now for input 1022. How can I make the program a bit faster? How can I increase the efficiency of program? Is there a faster algorithm?

I have Intel Core2 Duo (2.93GHz).

#include <stdio.h>
int main() {
    unsigned long long n;
    double m;
    double sum=0;
    scanf("%llu", &n);
    while (n>0) {
        m=1.0/n;
        sum+=m;
        n--;
    }
    printf("%lf",sum);
    return(0);
}
\$\endgroup\$
2
  • 2
    \$\begingroup\$ You have an accuracy issue: even though you compute the smaller fractions first, the accumulated error after 10^22 iterations is substantial. I wouldn't be surprised if the result was completely inaccurate. You should analyse this seriously before focussing on speed. \$\endgroup\$
    – chqrlie
    Commented Apr 5, 2015 at 12:55
  • \$\begingroup\$ Also note that "%lf" is equivalent to "%f" l has no effect on f in printf, unlike scanf. The format to print long double is "%Lf". \$\endgroup\$
    – chqrlie
    Commented Apr 5, 2015 at 13:02

1 Answer 1

3
\$\begingroup\$

To illustrate my comment about accuracy, I wrote a small test program:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    unsigned long long n;
    double sum = 0;
    float fsum = 0;
    long double lsum = 0;

    if (argc > 1)
        n = strtoull(argv[1], NULL, 0);
    else
        scanf("%llu", &n);

    while (n > 0) {
        /* computing using double arithmetic */
        double m = 1.0 / n;
        sum += m;
        /* computing using float arithmetic */
        float fm = (float)1 / n;
        fsum += fm;
        /* computing using long double arithmetic */
        long double lm = (long double)1 / n;
        lsum += lm;
        n--;
    }
    printf("long double: %Lf\n", lsum);
    printf("double: %f, delta=%Lg\n", sum, lsum - sum);
    printf("float: %f, delta=%f\n", fsum, sum - fsum);
    return 0;
}

The following tests give this output:

~/dev/stackoverflow > time ./t41 10000000
long double: 16.695311
double: 16.695311, delta=-1.12868e-13
float: 16.686031, delta=0.009280

real  0m0.257s
user  0m0.244s
sys   0m0.004s

~/dev/stackoverflow > time ./t41 100000000
long double: 18.997896
double: 18.997896, delta=4.51783e-13
float: 18.807919, delta=0.189978

real  0m2.585s
user  0m2.558s
sys   0m0.010s

~/dev/stackoverflow > time ./t41 1000000000
make: `t41' is up to date.
long double: 21.300482
double: 21.300482, delta=1.79655e-12
float: 18.807919, delta=2.492563

real  0m25.287s
user  0m25.116s
sys   0m0.073s

My machine is not very fast, but it would take 10^13 seconds to complete the calculation for 10^22 using your code. Given the estimated age of the universe, 5.10^17 seconds, you should kill the process and think about a better algorithm.

Looking at the accumulated error for just 10^9 iterations between long double and double, computing in double for 10^13 more iterations would given useless results.

\$\endgroup\$
3
  • \$\begingroup\$ Why should my code acumulate error? I don't get your program please explain! Thank you very much! \$\endgroup\$ Commented Apr 5, 2015 at 13:23
  • 2
    \$\begingroup\$ Your code accumulates errors because floating point operations have limited accuracy. Mine does too. My program illustrates how this limited accuracy quicky becomes problematic. float computation is completely off, double is visibly less accurate than long double. If n becomes very large, even long double would not be accurate enough. \$\endgroup\$
    – chqrlie
    Commented Apr 5, 2015 at 13:30
  • \$\begingroup\$ The harmonic sum of integers between 1 and n converges to log(n)+γ, γ (gamma) being the Euler-Mascheroni constant. Check this for other algorithms: en.wikipedia.org/wiki/Euler%E2%80%93Mascheroni_constant \$\endgroup\$
    – chqrlie
    Commented Apr 5, 2015 at 13:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.