I am trying to do problem 12 in Project Euler.
numDivisor64 is to calculate number of divisors.
I wrote this F# code:
let problem12 =
{1L..300000L} |> Seq.map (fun x->x*(x+1L)/2L) |> Seq.map numDivisor64 |> Seq.filter (fun x->x>500L)
The problem asks to find the number rather than its # of divisors. Besides writing this in a less compact way using loops or recursion, any beautiful method?
Another problem, I occasionally find that I need to convert a 32-bit int version of code to a 64-bit one by adding 'L' to all the numbers. Is there a way to avoid this? Anything like c++ template?
I first wrote
let numDivisor n =
let rec countd n d =
if n%d=0 then
let n2, cnt = countd (n/d) d
n2, cnt+1
else
n, 0
let rec collect n d =
if n < d then 1
elif n%d=0 then
let n2, cnt = countd n d
(cnt+1) * (collect n2 d)
else
collect n (d+1)
collect n 2
Later I found I need bigger integers:
let numDivisor64 n =
let rec countd n d =
if n%d=0L then
let n2, cnt = countd (n/d) d
n2, cnt+1L
else
n, 0L
let rec collect n d =
if n < d then 1L
elif n%d=0L then
let n2, cnt = countd n d
(cnt+1L) * (collect n2 d)
else
collect n (d+1L)
collect n 2L
I would rephrase the search for the first wanted number as follows:
start with an infinite stream of int64's
turn them into triangle numbers
find the first number that satisfies the condition (instead of mapping to the number of divisors, which is not what you want, you want the number itself).
code:
let problem12 =
Seq.initInfinite int64 //the same as Seq.initInfinite (fun n -> int64 n)
|> Seq.map (fun x -> x*(x+1L)/2L)
|> Seq.find (fun x -> numDivisor64 x > 500L)
Regarding the second problem: when I solve project Euler problems I usually use int64's by default, because of type inference restrictions.
It's possible to write a more generic version using the inline keyword. See for instance this thread over at hubFS.
EDIT: here's a more generic version, using the technique described in the above link:
The type signature of NumDivisorG becomes horrible, but should work for any data type that 'knows' *,+,1 and 0.
module NumericLiteralG =
let inline FromZero() = LanguagePrimitives.GenericZero
let inline FromOne() = LanguagePrimitives.GenericOne
let inline numDivisorG n =
let rec countd n d =
if n%d=0G then
let n2, cnt = countd (n/d) d
n2, cnt+1G
else
n, 0G
let rec collect n d =
if n < d then 1G
elif n%d=0G then
let n2, cnt = countd n d
(cnt+1G) * (collect n2 d)
else
collect n (d+1G)
collect n (1G+1G)
let problem12L =
Seq.initInfinite int64 //the same as Seq.initInfinite (fun n -> int64 n)
|> Seq.map (fun x -> x*(x+1L)/2L)
|> Seq.find (fun x -> numDivisorG x > 500L)
let problem12I =
Seq.initInfinite id //the same as Seq.initInfinite (fun n -> n)
|> Seq.map (fun x -> x*(x+1)/2)
|> Seq.find (fun x -> numDivisorG x > 500)
if you have the list of divisors you could write a function to calculate the lowest common multiple of them all (which should be the number in question).
in haskell this looks like
lcmAll = foldl1 lcm
in F# i think it would look like this
let rec lcmAll ( head :: tail ) =
Seq.fold lcm head tail
I'm not sure if F# has a builtin lcm.
The alternative to this is to carry the original number around through all the transformations by using a product type, or tuple.
let problem12 =
{1L..300000L} |> Seq.map (fun x->x*(x+1L)/2L) |> Seq.map (fun x->(x,numDivisor64 x)) |> Seq.filter (fun (x,y)->y>500L)
In regards to the 64 bit number issue, if you give your function an explicit type signature it could force F# to use 64-bit ints (provided the type signature is valid for the function definition). Again this sort of thing works in Haskell, I cannot confirm it does with F#. If you could double check that would be awesome.
Related
I'm having a problem with understanding how F# works. I come from C# and I think that I'm trying to make F# work like C#. My biggest problem is returning values in the correct format.
Example:
Let's say I have function that takes a list of integers and an integer.
Function should print a list of indexes where values from list match passed integer.
My code:
let indeks myList n = myList |> List.mapi (fun i x -> if x=n then i else 0);;
indeks [0..4] 3;;
However it returns:
val it : int list = [0; 0; 0; 3; 0]
instead of just [3] as I cannot ommit else in that statement.
Also I have targeted signature of -> int list -> int -> int list and I get something else.
Same goes for problem no. 2 where I want to provide an integer and print every number from 0 to this integer n times (where n is the iterated value):
example:
MultiplyValues 3;;
output: [1;2;2;3;3;3]
Best I could do was to create list of lists.
What am I missing when returning elements?
How do I add nothing to the return
example: if x=n then n else AddNothingToTheReturn
Use List.choose:
let indeks lst n =
lst
|> List.mapi (fun i s -> if s = n then Some i else None)
|> List.choose id
Sorry, I didn't notice that you had a second problem too. For that you can use List.collect:
let f (n : int) : list<int> =
[1 .. n]
|> List.collect (fun s -> List.init s (fun t -> s))
printfn "%A" (f 3) // [1; 2; 2; 3; 3; 3]
Please read the documentation for List.collect for more information.
EDIT
Following s952163's lead, here is another version of the first solution without the Option type:
let indeks (lst : list<int>) (n : int) : list<int> =
lst
|> List.fold (fun (s, t) u -> s + 1, (if u = n then (s :: t) else t)) (0, [])
|> (snd >> List.rev)
This one traverses the original list once, and the (potentially much shorter) newly formed list once.
The previous answer is quite idiomatic. Here's one solution that avoids the use of Option types and id:
let indeks2 lst n =
lst
|> List.mapi (fun i x -> (i,x))
|> List.filter (fun x -> (fst x) % n = 0 )
|> List.map snd
You can modify the filter function to match your needs.
If you plan to generate lots of sequences it might be a good idea to explore Sequence (list) comprehensions:
[for i in 1..10 do
yield! List.replicate i i]
If statements are an expression in F# and they return a value. In this case both the IF and ELSE branch must return the same type of value. Using Some/None (Option type) gets around this. There are some cases where you can get away with just using If.
Very often when writing generic code in F# I come by a situation similar to this (I know this is quite inefficient, just for demonstration purposes):
let isPrime n =
let sq = n |> float |> sqrt |> int
{2..sq} |> Seq.forall (fun d -> n % d <> 0)
For many problems I can use statically resolved types and get even a performance boost due to inlining.
let inline isPrime (n:^a) =
let two = LanguagePrimitives.GenericOne + LanguagePrimitives.GenericOne
let sq = n |> float |> sqrt |> int
{two..sq} |> Seq.forall (fun d -> n % d <> LanguagePrimitives.GenericZero)
The code above won't compile because of the upper sequence limit being a float. Nongenerically, I could just cast back to int for example.
But the compiler won't let me use any of these:
let sq = n |> float |> sqrt :> ^a
let sq = n |> float |> sqrt :?> ^a
and these two lead to a InvalidCastException:
let sq = n |> float |> sqrt |> box |> :?> ^a
let sq = n |> float |> sqrt |> box |> unbox
Also, upcast and downcast are forbidden.
let sq = System.Convert.ChangeType(n |> float |> sqrt, n.GetType()) :?> ^a works, but seems very cumbersome to me.
Is there a way that I overlooked or do I really have to use the last version? Because the last one will also break for bigint, which I need quite often.
With the trick from FsControl, we can define generic function fromFloat:
open FsControl.Core
type FromFloat = FromFloat with
static member instance (FromFloat, _:int32 ) = fun (x:float) -> int x
static member instance (FromFloat, _:int64 ) = fun (x:float) -> int64 x
static member instance (FromFloat, _:bigint ) = fun (x:float) -> bigint x
let inline fromFloat (x:float):^a = Inline.instance FromFloat x
let inline isPrime (n:^a) =
let two = LanguagePrimitives.GenericOne + LanguagePrimitives.GenericOne
let sq = n |> float |> sqrt |> fromFloat
{two..sq} |> Seq.forall (fun d -> n % d <> LanguagePrimitives.GenericZero)
printfn "%A" <| isPrime 71
printfn "%A" <| isPrime 6L
printfn "%A" <| isPrime 23I
Inline.instance was defined here.
I am trying to churn out a list of randoms and turn it into a vector using MathNet.Numerics. But my F# Interactive returns(below) instead of the values generated. Below is my code.
val cumRC : DenseVector
would expect to return something like this.
cumRC : float list =
[0.9888577146; 1.013791155; 0.9816407702; 0.9967110693; 1.000800844;
1.004584863; 0.999112488; 0.9908830826; 1.009421593; 1.00276232]
open MathNet.Numerics
open MathNet.Numerics.Distributions
open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.LinearAlgebra.Double
open MathNet.Numerics.LinearAlgebra.Generic.FSharpExtensions
let genRandom count =
let rnd = Normal(0.0,1.0)
List.init count (fun _ -> 1.0 + rnd.Sample()/100.0)
let va = genRandom 10
let cumVa = List.scan (fun numbers n -> numbers * n) 1.0 va |> List.tail |> DenseVector.ofList
I have not used MathNet but removing the parts that are specific to that package produces the expected results. So the code with the MathNet parts stripped out is:
let rnd = new System.Random()
let genRandom count =
List.init count (fun _ -> rnd.Next())
let va = genRandom 10
let cumVa = List.scan (fun numbers n -> numbers * n) 1 va |> List.tail
Which produces:
val cumVa : int list =
[893568767; -84811745; 1485049601; -1376682691; -278974486; -902716576;
-1616974272; 1049846592; -1969542592; -2077634944]
So most likely place to look is the documentation for DenseVector. A quick google says that it doesn't have an ofList function.
I have been trying to wrap my head around fold_left and fold_right. As practice, I have been trying to rewrite a lot of functions in fold_left and fold_right to strengthen my knowledge. For instance, in finding the average of a list, I would calculate the sum and the length of the list using folds.
let sum_l xs = List.fold_left (fun x y -> x + y) 0 xs;;
let len_l xs = List.fold_left (fun x _ -> x + 1) 0 xs;;
And then I would move on to find the average. Here is my question. Is it possible to both these values in one single fold_left? How should I write the anonymous function? Thanks!
You just have to use a pair as your accumulator:
# let sum_and_len xs = List.fold_left (fun (s,l) x -> s+x, l+1) (0,0) xs;;
val sum_and_len : int list -> int * int = <fun>
# sum_and_len [0;1;2;3];;
- : int * int = (6, 4)
I'm learning OCaml (so forgive my style) and am trying to write a function that generates a list of prime numbers up to some upper bound. I've managed to do this in several different ways, all of which work until you scale them to a relatively high upper bound.
How can I change these (any of them) so that the recursion doesn't fill up the stack? I thought my while loop version would achieve this, but apparently not!
Generator
let primes max =
let isPrime p x =
let hasDivisor a = (x mod a = 0) in
not (List.exists hasDivisor p) in
let rec generate p test =
if test < max then
let nextTest = test + 2 in
if isPrime p test then generate (test :: p) nextTest
else generate p nextTest
else p in
generate [5; 3; 2] 7;;
This has been my most successful solution insofar as it doesn't immediately overflow the stack when running primes 2000000;;. However it just sits there consuming CPU; I can only assume it will complete eventually! The following alternatives all have the stack overflow problem:
Recursive Sieve of Eratosthenes
let primes max =
let rec sieve found toTest =
let h = List.hd toTest
and t = List.tl toTest in
let newPrimes = h :: found
and doesntDivide x = (x mod h <> 0) in
let nonDivisors = List.filter doesntDivide t in
if nonDivisors = [] then newPrimes
else sieve newPrimes nonDivisors in
let rec range a b =
if a > b then []
else a :: range (a + 1) b in
let p = range 2 max in
sieve [] p;;
Recursive Sieve of Eratosthenes v2
let primes max =
let rec sieve toTest =
let h = List.hd toTest
and t = List.tl toTest in
let doesntDivide x = (x mod h <> 0) in
let nonDivisors = List.filter doesntDivide t in
if nonDivisors = [] then [h]
else (h :: sieve nonDivisors) in
let rec range a b =
if a > b then []
else a :: range (a + 1) b in
let p = range 2 max in
sieve p;;
While Loop Sieve of Eratosthenes
let primes max =
let rec range a b =
if a > b then []
else a :: range (a + 1) b in
let tail = ref (range 2 max)
and p = ref [] in
while !tail <> [] do
let h = List.hd !tail
and t = List.tl !tail in
let doesntDivide x = (x mod h <> 0) in
let newTail = ref (List.filter doesntDivide t) in
tail := !newTail;
p := h :: !p
done;
!p;;
The stack overflows occur because your range function is not tail recursive. One that works is, e.g.
let rec range store a b =
if a > b then store
else range (a :: store) (a + 1) b
in
let p = List.rev (range [] 2 max) in
With that definition, and a format line, gives
$ ocamlopt -o primes2 primes2.ml
$ ./primes2
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
...
Since you're learning, I'll give you some unsolicited style comments as well :)
Don't use hd and tl. Prefer pattern matching. Then the compiler can tell you the cases you missed. E.g.
let rec sieve found toTest =
let h = List.hd toTest
and t = List.tl toTest in
would be
let rec sieve found = function
| h :: t -> ...
| [] -> Error handling...
Don't use x = []. Use pattern patching.
match x with
| [] -> ...
| h::t -> ...
Use anonymous functions rather than short (i.e. <= 1 line) named single use functions:
let doesntDivide x = (x mod h <> 0) in
let nonDivisors = List.filter doesntDivide t in
let nonDivisors = List.filter (fun x -> (x mod h <> 0)) t in
Use imperative features sparingly.
Your algorithms that you claim are the Sieve of Eratosthenes actually are not; they use trial division instead of sieving, which is easy to spot by looking for a comparison of a remainder (the mod operator) to zero. Here's a simple implementation of the Sieve of Eratosthenes, in pseudocode instead of Ocaml because it's been a long time since I wrote Ocaml code:
function primes(n)
sieve := makeArray(2..n, True)
for p from 2 to n
if sieve[p]
output p
for i from p*p to n step p
sieve[i] := False
That can be optimized further, though for small limits like n = 2000000 there is little point in doing so; in any case, a sieve will be very much faster than the trial division that you are using. If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.