2016-04-01 16 views
4
(product (take 9 [1000,999..])) `div` (product (map (\j-> product [1..j]) (map (\j->length(j)) (group [2,2,2,2,2,2,2,2,2])))) 

Der obige Code ist von der Form X div Y, mit X=product (take 9 [1000,999..]) & Y=(product (map (\j-> product [1..j]) (map (\j->length(j)) (group [2,2,2,2,2,2,2,2,2]))))Große Zahlen negativ werden in Haskell

Wenn ich den Code in GHCI kopieren und einfügen, es gibt mir -12740133310672 als Antwort, aber wenn ich X & Y einzeln zähle, bekomme ich 964541486381834014456320000 & 362880, dann gibt sie mir 2658017764500203964000 als Antwort.

Ich denke, diese Inkohärenz könnte sein, weil die Zahl zu groß ist, aber da der Computer X und Y richtig einzeln berechnen kann, wie kann es sie nicht auch kombiniert teilen?

+5

es ist nur die "Länge" drin - dies wird das Ergebnis auf "Int" beschränken, aber Sie wollen wirklich "Integer" - verwenden Sie '(\ j -> fromIntegral $ length j)' was nur 'fromIntegral ist. Länge statt – Carsten

+4

als Alternative könnten Sie auch ['genericLength'] (https://hackage.haskell.org/package/base-4.8.2.0/docs/Data-List.html#v:genericLength) verwenden, um – Carsten

+1

btw: das letzte Parth ist wirklich seltsam, da der letzte Teil nur "[9]" usw. ist. – Carsten

Antwort

10
Prelude Data.List> let x = product $ take 9 [1000,999..] 

Prelude Data.List> x 
964541486381834014456320000 
Prelude Data.List> :t x 
x :: (Enum a, Num a) => a 

beachten Sie, dass x hat den Typ einer generic Nummer. Sie es mit nur Operationen berechnet, die für jede Nummerntyp arbeiten, wenn Sie eine solche Nummer in GHCi bewerten, wird standardmäßig die “ sichersten ” Betontyp, der Integer ist, ein beliebiger Präzisionstyp, der bei großen Zahlen kein Problem hat. Sie können jedoch die Berechnung erzwingen zu mit einem anderen numerischen Typ erfolgen:

Prelude Data.List> x :: Integer 
964541486381834014456320000 
Prelude Data.List> x :: Float 
9.645414e26 
Prelude Data.List> x :: Double 
9.645414863818342e26 
Prelude Data.List> x :: Int 
-4623139575776374784 

Die Gleitkomma-Versionen sind ungenau, aber immer noch nahe, während Int (eine maschine feste Größe Präzision Nummer) einfach überläuft und gibt kompletten Schein .

Normalerweise stört Sie das nicht, da große Berechnungen standardmäßig mit dem sicheren Typ Integer durchgeführt werden.

Das ist, es sei denn, etwas anderes verhindert es.

Prelude Data.List> let y = product (map (\j-> product [1..j]) $ map length (group [2,2,2,2,2,2,2,2,2])) 

Prelude Data.List> y 
362880 
Prelude Data.List> :t y 
y :: Int 

Im Gegensatz zu x, ist die Art der y bereits konkret: es Int sein muss, denn das ist der Ergebnistyp von length ist. (Die Begründung Wesen: eine Liste, die so groß ist, dass man nicht seine Länge mit einem Int messen könnte, wäre im Speicher nicht in der Lage sein, auf jeden Fall passen.)

Nun div, wie die meisten numerischen Funktionen in Haskell, erfordern, dass die Argumente und Ergebnis haben alle denselben Typ. Aus diesem Grund wird x`div`y als Ganzes als Int anstelle von Integer berechnet, einschließlich x. Und wie wir gesehen haben, gibt die Berechnung x als Int betrügerisch.

OTOH, wenn Sie 362880 als Literal verwenden, dann ist dies nicht mit length verbunden. Es ist nur eine allgemeine Zahl, wie x, daher wird GHCi wieder standardmäßig sicher Integer, dh Sie

Prelude Data.List> x `div` 362880 
2658017764500203964000 

Das gleiche Ergebnis erreicht werden kann, wenn man nur Umwandlung von y erlauben:

Prelude Data.List> x `div` fromIntegral y 
2658017764500203964000 
+0

Uhh - Ich sehe, er hat wirklich nur das Ergebnis eingefügt, den wörtlichen Wert. Jetzt macht alles Sinn! Gute Antwort! – robert

0

Mit Integer statt Int hilft:

let r :: Integer ; r = (product (take 9 [1000,999..])) `div` (product (map (\j-> product [1..j]) (map (\j->fromIntegral $ length(j)) (group [2,2,2,2,2,2,2,2,2])))) 

bringt mich: 2658017764500203964000

ich Ihren Code verstanden nicht vollständig, aber ich nehme an, wenn man sie einzeln berechnen Sie kleinere Zwischenergebnisse erhalten - so Int wird nicht überlaufen.

Also ja - die Inkohärenz ist wegen der großen Zahlen (Int ist in seiner Breite begrenzt, so wird es nur Überlauf (negative Zahlen). Wenn Sie mit so großen Zahlen arbeiten, sollten Sie wahrscheinlich Integer verwenden, die unbegrenzte Breite hat.

+0

Haskell wird X und Y nicht zuerst berechnen und dann teilen? Da Haskell sie einzeln berechnen kann, wie kann es nicht X Dividieren Y berechnen, was eine kleinere Zahl ergibt? – CYC

+0

Nein, das tut es. Deine individuellen Berechnungen funktionieren nicht für mich - ich werde später nachsehen müssen. – robert