Today I saw the D's pi computing sample (\dmd\samples\d\pi.d) and thought that porting it to c++ and c# for making a little benchmark should be easy:
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));
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 * multiplier + carry);
digit = b % 10;
carry = b / 10;
t = digit;
}
}
/* t[] /= l */
void div(int divisor)
{
int i, b;
int quotient, remainder = 0;
for (i = 0; i <= q; i++) {
b = (10 * remainder + t);
quotient = b / divisor;
remainder = b % divisor;
t = quotient;
}
}
void div4()
{
int i, c, d = 0;
for (i = 0; i <= q; i++) {
c = (10 * d + p) / 4;
d = (10 * d + p) % 4;
p = c;
}
}
void mul4()
{
int i, c, d;
d = c = 0;
for (i = q; i >= 0; i--) {
d = (p * 4 + c) % 10;
c = (p * 4 + c) / 10;
p = 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=0;
t=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));
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 * multiplier + carry);
digit = b % 10;
carry = b / 10;
t = digit;
}
}
/* t[] /= l */
void div(int divisor)
{
int i, b;
int quotient, remainder = 0;
for (i = 0; i <= q; i++) {
b = (10 * remainder + t);
quotient = b / divisor;
remainder = b % divisor;
t = quotient;
}
}
void div4()
{
int i, c, d = 0;
for (i = 0; i <= q; i++) {
c = (10 * d + p) / 4;
d = (10 * d + p) % 4;
p = c;
}
}
void mul4()
{
int i, c, d;
d = c = 0;
for (i = q; i >= 0; i--) {
d = (p * 4 + c) % 10;
c = (p * 4 + c) / 10;
p = 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);
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 * multiplier + carry);
digit = b % 10;
carry = b / 10;
t = (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);
quotient = b / divisor;
remainder = b % divisor;
t = (sbyte)quotient;
}
}
void div4()
{
int i, c, d = 0;
for (i = 0; i <= q; i++)
{
c = (10 * d + p) / 4;
d = (10 * d + p) % 4;
p = (sbyte)c;
}
}
void mul4()
{
int i, c, d;
d = c = 0;
for (i = q; i >= 0; i--)
{
d = (p * 4 + c) % 10;
c = (p * 4 + c) / 10;
p = (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]