So wollen wir eine ganze Zahl finden n
so dass (n+1)*n/2 <= y < (n+2)*(n+1)/2
die quadratische Gleichung lösen f(x)=y
, wo f(x)=(x+1)*x/2
kann mit Fließkomma-Arithmetik durchgeführt werden, wobei dann n
als ganzzahliger Teil von x
genommen wird.
aber wir haben nicht wirklich Gleitkomma brauchen, weil wir nur den ganzzahligen Teil des Ergebnisses wollen, können wir es auch tun, mit einem Newton-Raphson Iteration https://en.wikipedia.org/wiki/Newton%27s_method
Die Ableitung von f(x)
f'(x)=(x+(1/2))
ist.Nicht eine gute ganze Zahl, aber wir können alle mit 2 multiplizieren, und schreiben Sie die Schleife wie folgt aus: (dies ist Smalltalk, aber das ist nicht wirklich wichtig):
Integer>>invSumFloor
"Return the integer n such that (1 to: n) sum <= self < (1 to: n+1) sum"
| guess delta y2 |
y2 := self * 2.
guess := 1 bitShift: y2 highBit + 1 // 2.
[
delta := ((guess + 1) * guess - y2) // (guess * 2 + 1).
delta = 0 ]
whileFalse: [ guess := guess - delta ].
^guess - 1
So wir so iterieren:
x(n+1) = x(n) - (2*f(x(n))-2*y)/(2*f'(x(n)))
Aber anstatt eine genaue Division zu nehmen, verwenden wir //
, was der Quotient auf die nächste ganze Zahl abgerundet ist.
Normalerweise sollten wir testen, ob die Schätzung in der Endphase überschätzt wird oder nicht.
Aber hier, wir arrangieren, dass die anfängliche Schätzung eine Überschätzung des Ergebnisses sein wird, aber nicht zu sehr überschätzt, so dass die Rate immer überschätzt bleibt. So können wir in der Endphase einfach 1 subtrahieren. Die obige Implementierung verwendet eine grobe Schätzung der ersten Bitposition als anfänglichen Wert x
.
Wir können dann überprüfen Sie die Implementierung auf den ersten zehntausend natürliche Zahlen mit:
(1 to: 10000) allSatisfy: [:y |
| n sum |
n := y invSumFloor.
sum := (1 to: n) sum.
(sum <= y and: [y < (sum + n + 1)])].
die true
Antworten
Was mit Smalltalk schön ist, dass man dann Dinge wie diese versuchen:
80 factorial invSumFloor.
Und erhalten Sie etwas wie:
378337037695924775539900121166451777161332730835021256527654
Sie sehen hier, dass Newton Raphson schnell konvergiert (7 Iterationen im obigen Beispiel). Dies unterscheidet sich sehr von der ursprünglichen naiven Iteration.
Die Lösung der quadratischen Gleichung scheint eine sehr gute Idee zu sein. – Tempux
Aber ich fühle, dass es einen besseren Weg geben kann – roang
Besser in welcher Weise? – Tempux