ty nadal rozumiesz, że największy problemem jest to, że wpadłeś na forum i zacząłeś swoją karierę od obrażania ludzi.
Twoje rozwiązanie z liczbami doble zadziała, ale dopiero po rozwiązaniu problemów z precyzją liczb zmiennoprzecinkowych. A pomysł ze wzorem Stirlinga to kompletny niewypał, dowód testami (może będziesz umiał je uruchomić):
Kopiuj
#include <QString>
#include <QtTest>
#include <cmath>
uint NewtonInts(uint n, uint k)
{
if (2*k<n) {
k = n - k;
}
register quint64 r = 1;
for (uint i=1; i<=k; ++i, --n)
r = r * n / i;
return r;
}
uint NewtonDoubles(uint n, uint k)
{
if (2*k<n) {
k = n - k;
}
double a = 1, b = 1;
for (uint i=n; i>n-k; --i) {
a *= i;
}
for (uint i=2; i<=k; ++i) {
b *= i;
}
return a/b + 0.5;
}
double Stirling(double n)
{
return sqrt(2*M_PI*n)*std::pow(n / M_E, n);
}
uint NewtonStirling(uint n, uint k)
{
return Stirling(n)/(Stirling(k)*Stirling(n-k)) + 0.5;
}
class NewtonRozneMetodyTest : public QObject
{
Q_OBJECT
public:
NewtonRozneMetodyTest();
private Q_SLOTS:
void testNewtonInts();
void testNewtonDoubles();
void testNewtonStirling();
};
NewtonRozneMetodyTest::NewtonRozneMetodyTest()
{
}
void NewtonRozneMetodyTest::testNewtonInts()
{
uint a,b,c,d;
QBENCHMARK {
a = NewtonInts(32, 15);
b = NewtonInts(33, 15);
c = NewtonInts(34, 14);
d = NewtonInts(35, 13);
}
QCOMPARE(a, 565722720u);
QCOMPARE(b, 1037158320u);
QCOMPARE(c, 1391975640u);
QCOMPARE(d, 1476337800u);
}
void NewtonRozneMetodyTest::testNewtonDoubles()
{
uint a,b,c,d;
QBENCHMARK {
a = NewtonDoubles(32, 15);
b = NewtonDoubles(33, 15);
c = NewtonDoubles(34, 14);
d = NewtonDoubles(35, 13);
}
QCOMPARE(a, 565722720u);
QCOMPARE(b, 1037158320u);
QCOMPARE(c, 1391975640u);
QCOMPARE(d, 1476337800u);
}
void NewtonRozneMetodyTest::testNewtonStirling()
{
uint a,b,c,d;
QBENCHMARK {
a = NewtonStirling(32, 15);
b = NewtonStirling(33, 15);
c = NewtonStirling(34, 14);
d = NewtonStirling(35, 13);
}
QCOMPARE(a, 565722720u);
QCOMPARE(b, 1037158320u);
QCOMPARE(c, 1391975640u);
QCOMPARE(d, 1476337800u);
}
#include "tst_newtonroznemetodytest.moc"
Wynik na mobilnym procku 1,6 GHz Intel Core i5
Kopiuj
********* Start testing of NewtonRozneMetodyTest *********
Config: Using QtTest library 5.5.0, Qt 5.5.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by Clang 6.0 (clang-600.0.56) (Apple))
PASS : NewtonRozneMetodyTest::initTestCase()
PASS : NewtonRozneMetodyTest::testNewtonInts()
RESULT : NewtonRozneMetodyTest::testNewtonInts():
0.0000084 msecs per iteration (total: 71, iterations: 8388608)
PASS : NewtonRozneMetodyTest::testNewtonDoubles()
RESULT : NewtonRozneMetodyTest::testNewtonDoubles():
0.0000078 msecs per iteration (total: 66, iterations: 8388608)
FAIL! : NewtonRozneMetodyTest::testNewtonStirling() Compared values are not the same
Actual (a) : 570182287
Expected (565722720u): 565722720
Loc: [../NewtonRozneMetody/tst_newtonroznemetodytest.cpp(99)]
PASS : NewtonRozneMetodyTest::cleanupTestCase()
Totals: 4 passed, 1 failed, 0 skipped, 0 blacklisted
********* Finished testing of NewtonRozneMetodyTest *********
To dowodzi, że wersja zmiennoprzecinkowa jest nieznacznie szybsza niż wersja na liczbach całkowitych (przy mniejszych wartościach jest na odwrót).
A pomysł ze wzorem Stirlinga jest kretyński (wzór Stirlinga jest efektywny dla dużych wartości, 40 to dużo za mało), na dodatek wolniejszy niż wersja int.
Przeiterowałem wszystkie dane wejściowe dla n od 1 do 50 i wszystkie możliwe k, wyniki są te same (nawet te same błędy) dla wersji z uint i double.
Dla twojej informacji: jest jeszcze szybsze cwane rozwiązanie, które bije na głowę wszystkie powyższe.