Das ist nicht kurz und sicherlich nicht effizient, aber es ist ein anderer Weg:
scala> Iterator.iterate(BigInt(123))(_/10).takeWhile(_>0).map(_%10).sum
res1: scala.math.BigInt = 6
(und Sie wollen wahrscheinlich eine Int
was ohnehin schneller ist, aber eine .map(i=>(i%10).toInt)
.)
Das Problem bei dieser Methode (und der einfachen Rekursion) ist, dass man so viele Divisionen wie Ziffern berechnen muss. (Sie könnten verwenden /%
um die Dinge um den Faktor 2 zu beschleunigen, aber das ist immer noch ein Problem). Die Konvertierung in eine Zeichenkette ist viel schneller, weil all diese expliziten BigInt
Kreationen vermieden werden können.
Wenn Sie wirklich etwas wollen, das funktioniert schnell (nicht das, was Sie wollten, ich weiß), brauchen Sie einen Ansatz, bei dem Sie teilen und erobern:
def fastDigitSum(b: BigInt): Int = {
val bits = b.bitLength
if (bits < 63) math.abs(b.toLong).toString.map(_-'0').sum
else {
val many = 256
val zeros = math.ceil(bits*0.150515).toInt // constant is 0.5*log(2)/log(10)
val root = (
if (zeros<many) BigInt("1" + "0"*zeros)
else {
Iterator.iterate((BigInt("1"+"0"*many),many))(x => (x._1 * x._1, 2*x._2)).
find(_._2 > zeros/2).get._1
}
)
val (q,r) = b /% root
fastDigitSum(q) + fastDigitSum(r)
}
}
Bearbeiten: Wenn Sie möchten wirklich schnelle Konvertierungen bei allen Größen, habe ich mein Schema wie folgt geändert. Es gibt einige nicht ganz funktionsfähige Bits, die hauptsächlich auf das Fehlen eines takeTo
Methode. Dies sollte bei allen Größen schneller sein als alles andere (obwohl es asymptotisch zu fastDigitSum
Leistung für sehr große BigInts).
Wahrscheinlich läuft es auf 64-Bit-Maschinen besser als auf 32-Bit-Maschinen.
Bei der Herstellung dieser Funktion wurden keine Saiten beschädigt.
object DigitSum {
val memend = BigInt(10000000000000000L) :: BigInt(100000000) :: Nil
def longSum(l: Long, sum: Int = 0): Int = {
if (l==0) sum else longSum(l/10, sum + (l%10).toInt)
}
def bigSum(b: BigInt, memo: List[BigInt] = Nil): Int = {
val bits = b.bitLength
if (bits < 64) longSum(b.toLong)
else {
val mem = (
if (memo.isEmpty) {
val it = Iterator.iterate(memend.head)(x=>x*x).drop(1)
var xs = memend
while (xs.head.bitLength*4 <= bits) xs = it.next :: xs
xs
}
else memo.dropWhile(_.bitLength > bits/2)
)
val (q,r) = b /% mem.head
bigSum(q,memo) + bigSum(r,memo)
}
}
}
(Okay - das ist jetzt ein bisschen wie Code-Golf.)