P
SeppJ schrieb:
Dieses kleine Juwel darf natürlich auch nicht fehlen:
Oder gleich komplett mit Template-Metaprogrammierung, d.h. alles zur Compilezeit berechnet (ungetestet, mangels Compiler, bei dem die Tiefe einstellbar ist):
#include <iostream>
typedef unsigned long ul;
//metatyp fuer rationale Zahlen
template <ul zaehler, ul nenner> struct rational;
//Metafunktionen
template <ul z, ul n> struct kuerzen; //ergebnis: rational
template <ul a, ul b> struct ggt; //ergebnis: ul
template <class LHS, class RHS> struct add; //ergebnis: rational, falls LHS, RHS rational
template <class T> struct to_double; //ergebnis: double, falls T rational
template <ul n> struct accum; //ergebnis: rational
//to_double fuer rational
template <ul z, ul n>
struct to_double<rational<z,n> > { static double value; };
template <ul z, ul n>
double to_double<rational<z,n> >::value = (1.*z)/n;
//add fuer rational
template <ul zLHS, ul nLHS, ul zRHS, ul nRHS>
struct add<rational<zLHS, nLHS>, rational<zRHS, nRHS> >
{
typedef typename kuerzen<zLHS*nRHS+zRHS*nLHS, nLHS*nRHS>::type type;
};
//kuerzen eines bruches. ergebnis: rational
template <ul z, ul n>
struct kuerzen
{
typedef rational<z/ggt<n,z>::value, n/ggt<n,z>::value> type;
};
//groesster gemeinsamer teiler.
template <ul a>
struct ggt<a, 0ul>
{
const static ul value = a;
};
template <ul a, ul b>
struct ggt
{
const static ul value = (b>a) ? ggt<a, b%a>::value
: ggt<b, a%b>::value;
};
//aufsummieren der Reihe
template <>
struct accum<0>
{
typedef rational<1ul,1ul> type;
};
template <ul n>
struct accum
{
const static ul mm = (2*n+1)*(2*n+1);
typedef typename add<typename accum<n-1>::type,
rational<1,mm> >::type type;
};
int main()
{
using namespace std;
cout << to_double<accum<530947>::type>::value << endl;
}
als "normales" Programm sähe das so aus:
#include <iostream>
typedef unsigned long ul;
//typ fuer rationale Zahlen
struct rational
{
ul zaehler;
ul nenner;
};
rational kuerzen(ul z, ul n);
ul ggt(ul a, ul b);
rational add(rational lhs, rational rhs);
double to_double(rational t);
rational accum(ul n);
double to_double(rational t)
{
return (1.*t.zaehler)/t.nenner;
}
rational add(rational lhs, rational rhs)
{
return kuerzen(lhs.zaehler*rhs.nenner + rhs.zaehler*lhs.nenner, lhs.nenner*rhs.nenner);
}
rational kuerzen(ul z, ul n)
{
rational erg;
erg.zaehler = z/ggt(n,z);
erg.nenner = n/ggt(n,z);
return erg;
}
ul ggt(ul a, ul b)
{
if (b==0) return a; //(template-Spezialisierung)
return (b>a) ? ggt(a, b%a) : ggt(b, a%b);
}
rational accum(ul n)
{
if (n==0) //(template-Spezialisierung)
{
rational eins = {1ul, 1ul};
return eins;
}
rational summand;
summand.zaehler = 1;
summand.nenner = (2*n+1)*(2*n+1);
return add(accum(n-1), summand);
}
int main()
{
using namespace std;
cout << to_double(accum(530947)) << endl;
}
edith meint, dass das aber vermutlich irgendwo auf Überläufe stoßen wird