d:

import std.c.stdio; import std.c.stdlib; import std.c.time; const int LONG_TIME=4000; byte[] p; byte[] t; int q; int main(char[][] args) { int startime, endtime; int i; if (args.length == 2) { sscanf(&args[1][0],"%d",&q); } else { printf("Usage: pi [precision]\n"); exit(55); } if (q < 0) { printf("Precision was too low, running with precision of 0.\n"); q = 0; } if (q > LONG_TIME) { printf("Be prepared to wait a while...\n"); } // Compute one more digit than we display to compensate for rounding q++; p.length = q + 1; t.length = q + 1; /* compute pi */ std.c.time.time(&startime); arctan(2); arctan(3); mul4(); std.c.time.time(&endtime); // Return to the number of digits we want to display q--; /* print pi */ printf("pi = %d.",cast(int)(p[0])); for (i = 1; i <= q; i++) printf("%d",cast(int)(p[i])); printf("\n"); printf("%ld seconds to compute pi with a precision of %d digits.\n",endtime-startime,q); return 0; } void arctan(int s) { int n; t[0] = 1; div(s); /* t[] = 1/s */ add(); n = 1; do { mul(n); div(s * s); div(n += 2); if (((n-1) / 2) % 2 == 0) add(); else sub(); } while (!tiszero()); } void add() { int j; for (j = q; j >= 0; j--) { if (t[j] + p[j] > 9) { p[j] += t[j] - 10; p[j-1] += 1; } else p[j] += t[j]; } } void sub() { int j; for (j = q; j >= 0; j--) if (p[j] < t[j]) { p[j] -= t[j] - 10; p[j-1] -= 1; } else p[j] -= t[j]; } void mul(int multiplier) { int b; int i; int carry = 0, digit = 0; for (i = q; i >= 0; i--) { b = (t[i] * multiplier + carry); digit = b % 10; carry = b / 10; t[i] = digit; } } /* t[] /= l */ void div(int divisor) { int i, b; int quotient, remainder = 0; for (i = 0; i <= q; i++) { b = (10 * remainder + t[i]); quotient = b / divisor; remainder = b % divisor; t[i] = quotient; } } void div4() { int i, c, d = 0; for (i = 0; i <= q; i++) { c = (10 * d + p[i]) / 4; d = (10 * d + p[i]) % 4; p[i] = c; } } void mul4() { int i, c, d; d = c = 0; for (i = q; i >= 0; i--) { d = (p[i] * 4 + c) % 10; c = (p[i] * 4 + c) / 10; p[i] = d; } } int tiszero() { int k; for (k = 0; k <= q; k++) if (t[k] != 0) return false; return true; }

(I compiled pi.d with dmd -O -release pi.d)

c++:

#include <stdio.h> #include <stdlib.h> #include <time.h> #define LONG_TIME 4000 __int8* p; __int8* t; int q; void arctan(int s); void add(); void sub(); void mul(int); void div(int); void mul4(); void div4(); int tiszero(); int main(int argv,char** args) { time_t startime, endtime; int i; if (argv == 2) { sscanf(&args[1][0],"%d",&q); } else { printf("Usage: pi [precision]\n"); exit(55); } if (q < 0) { printf("Precision was too low, running with precision of 0.\n"); q = 0; } if (q > LONG_TIME) { printf("Be prepared to wait a while...\n"); } // Compute one more digit than we display to compensate for rounding q++; p = new __int8[ q + 1 ]; t = new __int8[ q + 1 ]; for(int tt=0;tt<=q;tt++) { p[tt]=0; t[tt]=0; } /* compute pi */ time(&startime); arctan(2); arctan(3); mul4(); time(&endtime); // Return to the number of digits we want to display q--; /* print pi */ printf("pi = %d.",(int)(p[0])); for (i = 1; i <= q; i++) printf("%d",(int)(p[i])); printf("\n"); printf("%ld seconds to compute pi with a precision of %d digits.\n",(long)endtime-(long)startime,q); delete [] p; delete [] t; return 0; } void arctan(int s) { int n; t[0] = 1; div(s); /* t[] = 1/s */ add(); n = 1; do { mul(n); div(s * s); div(n += 2); if (((n-1) / 2) % 2 == 0) add(); else sub(); } while (!tiszero()); } void add() { int j; for (j = q; j >= 0; j--) { if (t[j] + p[j] > 9) { p[j] += t[j] - 10; p[j-1] += 1; } else p[j] += t[j]; } } void sub() { int j; for (j = q; j >= 0; j--) if (p[j] < t[j]) { p[j] -= t[j] - 10; p[j-1] -= 1; } else p[j] -= t[j]; } void mul(int multiplier) { int b; int i; int carry = 0, digit = 0; for (i = q; i >= 0; i--) { b = (t[i] * multiplier + carry); digit = b % 10; carry = b / 10; t[i] = digit; } } /* t[] /= l */ void div(int divisor) { int i, b; int quotient, remainder = 0; for (i = 0; i <= q; i++) { b = (10 * remainder + t[i]); quotient = b / divisor; remainder = b % divisor; t[i] = quotient; } } void div4() { int i, c, d = 0; for (i = 0; i <= q; i++) { c = (10 * d + p[i]) / 4; d = (10 * d + p[i]) % 4; p[i] = c; } } void mul4() { int i, c, d; d = c = 0; for (i = q; i >= 0; i--) { d = (p[i] * 4 + c) % 10; c = (p[i] * 4 + c) / 10; p[i] = d; } } int tiszero() { int k; for (k = 0; k <= q; k++) if (t[k] != 0) return false; return true; }

c#:

using System; using System.Diagnostics; class Pi { static void Main(string[] args) { Pi pi = new Pi(); pi.run(args); } private const int LONG_TIME = 4000; sbyte[] p; sbyte[] t; int q; void run(string[] args) { Stopwatch timer = new Stopwatch(); int i; if (args.Length == 1) { q = int.Parse(args[0]); } else { Console.WriteLine("Usage: pi [precision]"); return; } if (q < 0) { Console.WriteLine("Precision was too low, running with precision of 0."); q = 0; } if (q > LONG_TIME) { Console.WriteLine("Be prepared to wait a while..."); } // Compute one more digit than we display to compensate for rounding q++; p = new sbyte[q + 1]; t = new sbyte[q + 1]; /* compute pi */ timer.Start(); arctan(2); arctan(3); mul4(); timer.Stop(); // Return to the number of digits we want to display q--; /* print pi */ Console.Write("pi = {0}.", p[0]); for (i = 1; i <= q; i++) Console.Write(p[i]); Console.WriteLine(); Console.WriteLine("{0} seconds to compute pi with a precision of {1} digits.", timer.ElapsedMilliseconds / 1000.0, q); return; } void arctan(int s) { int n; t[0] = 1; div(s); /* t[] = 1/s */ add(); n = 1; do { mul(n); div(s * s); div(n += 2); if (((n - 1) / 2) % 2 == 0) add(); else sub(); } while (!tiszero()); } void add() { int j; for (j = q; j >= 0; j--) { if (t[j] + p[j] > 9) { p[j] += (sbyte)(t[j] - 10); p[j - 1] += 1; } else p[j] += t[j]; } } void sub() { int j; for (j = q; j >= 0; j--) if (p[j] < t[j]) { p[j] -= (sbyte)(t[j] - 10); p[j - 1] -= 1; } else p[j] -= t[j]; } void mul(int multiplier) { int b; int i; int carry = 0, digit = 0; for (i = q; i >= 0; i--) { b = (t[i] * multiplier + carry); digit = b % 10; carry = b / 10; t[i] = (sbyte)digit; } } /* t[] /= l */ void div(int divisor) { int i, b; int quotient, remainder = 0; for (i = 0; i <= q; i++) { b = (10 * remainder + t[i]); quotient = b / divisor; remainder = b % divisor; t[i] = (sbyte)quotient; } } void div4() { int i, c, d = 0; for (i = 0; i <= q; i++) { c = (10 * d + p[i]) / 4; d = (10 * d + p[i]) % 4; p[i] = (sbyte)c; } } void mul4() { int i, c, d; d = c = 0; for (i = q; i >= 0; i--) { d = (p[i] * 4 + c) % 10; c = (p[i] * 4 + c) / 10; p[i] = (sbyte)d; } } bool tiszero() { int k; for (k = 0; k <= q; k++) if (t[k] != 0) return false; return true; } }

I used the release builds for the benchmark, here are the results:

d : 26 seconds to compute pi with a precision of 10000 digits.

c# : 34,745(34.745) seconds to compute pi with a precision of 10000 digits.

c++ : 15 seconds to compute pi with a precision of 10000 digits.

I do not want to start a language war... we had enough such wars in the past days and I have just made this benchmark because I saw the “What do you think of the D language?“ thread and was testing d.

I'm just surprised a little: I thought that D shouldn't be much slower than c++ and I thought that c# would be much faster. Maybe there is some optimization option I have not used(?)

What do you think about the results?

(maybe some one can test java)

(I really like the invariant and unittest features of D, are there equivalents for c#?)

-I can't reply until tomorrow-

[Edited by - Kambiz on October 7, 2006 2:02:45 AM]