Hamming numbers: Difference between revisions
→{{header|Elm}}: clean up code...
GordonBGood (talk | contribs) (→{{header|Elm}}: clean up code...) |
|||
Line 3,746:
=={{header|Elm}}==
The Elm language has many restrictions that make the implementation of the Hamming Number sequence algorithms difficult, as the classic Edsger Dijkstra algorithm as written in Haskell [[Hamming_numbers#The_classic_version]] cannot be written in Elm as current Elm forbids cyclic value references (the value "hamming" is back referenced three times), and the implementation wouldn't be efficient even if it could as the current Elm version 0.19.x has removed the "Lazy" package the would defer the memoization of the result of a computation as necessary in implementing Haskell's lazy lists. Thus, one has to implement memoization using a different data structure than a lazy list; however, all current Elm data structures are persistent/forbid mutation and can only implement some sort of Copy On Write (COW), thus there is no implementation of a linear array and the "Array" module is a tree based structure (with some concessions to data blocks for slightly better performance) that will have a logarithmic execution complexity when the size increases above a minimum. In fact, all Elm data structures that could be used for this also have a logarithmic response (Dict, Set, Array). The implementation of List is not lazy so new elements can't be added to the "tail" but need to be added to the "head" for efficiency, which means if one wants to add higher elements to a list in increasing order, one needs to (COW) reverse the List (twice) in order to do it!
The solution here uses a pure functional implementation of a Min Heap (Binary Heap) Priority Queue so that the minimum element can be viewed in O(1) time although inserting new elements/replacing elements still takes O(log n) time where "n" is the number of elements in the queue. As written, no queue needs to be maintained for the multiples of five, but two
To express the sequence, a Co-Inductive Stream (CIS) is used as a deferred execution (lazy) stream; it does not memoize computations (as discussed above) but that isn't necessary for this application where the sequence is only traversed once and consumed as being traversed.
In addition, in order to reduce the "BigInt" computation time, the calculations are done on the basis of a "Float" logarithmic
<syntaxhighlight lang="elm">module Main exposing ( main )
Line 3,759:
import BigInt
import Task exposing ( Task, succeed, perform, andThen )
import Html exposing (
import Browser exposing ( element )
import Time exposing ( now, posixToMillis )
Line 3,865:
let omin = case peekMinPQ bpq of
Just (lr, trv) -> LogRep lr trv
nm235 = multLR2 omin
nbpq = replaceMinPQ m235.lr m235.trv bpq
Line 3,874:
let omin = case peekMinPQ mpq of
Just (lr, trv) -> LogRep lr trv
nm35 = multLR3 omin
nmrg = if ltLogRep nm35 m5 then nm35 else m5
Line 3,890:
in CIS (0, 0, 0) <| \ () ->
next emptyPQ emptyPQ im235 imrg im35 im5
-- following code has to do with outputting to a web page using MUV/TEA...▼
type alias Model = { time: Int▼
, str1: String, str2: String, str3: String }▼
timemillis : () -> Task Never Int -- a side effect function
Line 3,903 ⟶ 3,896:
test : Int -> Cmd Msg -- side effect function chain (includes "perform")...
test lmt =
let msg1 = "The first 20 Hamming numbers are: " ++
timemillis()▼
▲ in timemillis()
|> andThen (\ strt ->
let rsltstr = hammingsLog() |> nthCIS (lmt - 1)
timemillis()
|> andThen (\ stop ->
succeed [msg1, msg2, msg3, rsltstr ++ " in "
|> perform Done
▲-- following code has to do with outputting to a web page using MUV/TEA...
▲ <| "The " ++ String.fromInt cLIMIT ++
▲ String.fromInt (stptm - mdl.time) ++
▲ " milliseconds." )
type Msg = Done Model
main : Program () Model Msg
main = -- starts with empty list of strings; views model of filled list...
element { init = \ _ -> (
, update = \ (Done mdl) _
▲ |> List.map showTrival
▲ |> String.join ", ") ++ ".")
▲ ("The 1691st Hamming number is " ++
▲ (hammingsLog() |> nthCIS 1691
▲ |> showTrival) ++ ".")
, subscriptions = \ _ -> Sub.none
, view =
{{out}}
<pre>The first 20 Hamming numbers are: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36.
The 1691st Hamming number is 2125764000.
The 1000000th Hamming number is
519298692278785094152510283943756293079298533583627301759029258223616000000000000000 in 756 milliseconds.</pre>
Do note that, due to the logarithmic response of the Min Heap Priority Queue, the execution time is logarithmic with number of elements evaluation and not linear as it would otherwise be, so if it takes 0.7 seconds to find the millionth Hamming number, it takes something about 10 seconds to find the ten millionth value instead of about 7 seconds. Considering that the generated "native" code is just JavaScript, it is reasonably fast and somewhat competitive with easier implementations in other languages such as F#.
=={{header|Erlang}}==
|