Hi, that is unrelated to the original post but as it is a comparison between C# and F# implementations of Sieve of Erastothenes I reasoned it will be better to post here than open a new thread.
So I was thinking of using some not so imperative techniques to implement the sieve on .NET. I came up with this for C# using LINQ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
class Program { public static List<int> Sieve(int max) { int[] numbers = new int[max - 1]; for (int i = 0; i < max - 1; i++) { numbers[i] = i + 2; } var ceiling = Math.Sqrt(max); var primes = new List<int>(); while (numbers[0] <= ceiling) { primes.Add(numbers[0]); numbers = (from r in numbers where r % numbers[0] != 0 select r).ToArray(); //alternatively //query = query.Where(i => i % first != 0).ToArray() } primes.AddRange(numbers); return primes; } static void Main(string[] args) { foreach (int i in Sieve(120)) { Console.WriteLine(i); } DateTime start = DateTime.Now; Console.WriteLine(Sieve(10000000).Count); Console.WriteLine("Time = " + DateTime.Now.Subtract(start).TotalMilliseconds); } }
As you can see I also timed it and the result on my machine was like 13 seconds for max value of 10000000
I came up with this implementation of F# (I am still a beginner in F# and I havent even got to use sequences yet but...):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
let sieve max = let ceiling = sqrt (float max) in let rec sieveStep (numbers, currentPrimes) = if float (List.hd numbers) > ceiling then (numbers, currentPrimes) else let newPrimes = currentPrimes @ [numbers.Head] in sieveStep (List.filter (fun x -> x % numbers.Head <> 0) numbers, newPrimes) in let (primesLeft, primes) = sieveStep ([2..max], []) in primes @ primesLeft;; let start = System.DateTime.Now;; 120 |> sieve |> List.iter (fun x -> printfn "%d" x);; printfn "%f" (System.DateTime.Now.Subtract(start)).TotalMilliseconds;;
I also timed this and the result was more than 90 seconds.
So my question is what brings this performance difference. I perfectly understand that neither of this is the perfect implementation (I know you can do it with boolean array and use the indexes for the most efficient implementation). I perfectly understand that the two implementations are a lot different. Arrays vs linked lists, iteration vs recursion, etc. However what is the thing in the F# implementation that brings that huge performance penalty. I even instanciate new array objects for every iteration in the C# implementation so even object allocation in recursive implementation has somewhat of equivalent in C# code.
I also would like to know if these implementations are good enough and readable in both languages in your opinion and how can they be improved with functional constructs.
Thank you for your time
Regarding performance:
I presume it took >90s for a number bigger than "120"? (For 120, it ran in 19ms on my machine.) Also, in your F# code, you are timing the printing of the entire list (the printing is what's slow), whereas for C# you just print the count. The use of "@" (append) in the loop is expensive; prefer to cons onto the front with "::". But the main difference is printing; compare apples to apples for a fairer comparison.
Oh yes sorry I did not notice what I pasted as output code.
I tested with 10 000 000 (same as C# version) and I printed .Length
then I removed even that because I reasoned that it may take a lot of time to find the length of a linked list but that did not do it either.
So it is not related to printing and not even measuring the length.
And how do I append an element to the end of the list without @ ? I cannot :: because it will create a list with 2 elements list and an int, right?
Wow, the performance difference between arrays and lists here seems to be pretty big.
Here it is with an array:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#light let sieve max = let ceiling = sqrt (float max) let rec sieveStep (numbers : array<_>, currentPrimes) = if float numbers.[0] > ceiling then (numbers, currentPrimes) else let newPrimes = numbers.[0] :: currentPrimes sieveStep (Array.filter (fun x -> x % numbers.[0] <> 0) numbers, newPrimes) let (primesLeft, primes) = sieveStep ([|2..max|], []) primes @ (List.of_array primesLeft) let start = System.DateTime.Now 10000000 |> sieve |> List.length |> printfn "%d" printfn "%f" (System.DateTime.Now.Subtract(start)).TotalMilliseconds
And it runs in about 12s on my box. Changing "numbers" to a list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#light let sieve max = let ceiling = sqrt (float max) let rec sieveStep (numbers, currentPrimes) = let firstNum = List.hd numbers if float firstNum > ceiling then (numbers, currentPrimes) else let newPrimes = firstNum :: currentPrimes sieveStep (List.filter (fun x -> x % firstNum <> 0) numbers, newPrimes) let (primesLeft, primes) = sieveStep ([2..max], []) primes @ primesLeft let start = System.DateTime.Now 10000000 |> sieve |> List.length |> printfn "%d" printfn "%f" (System.DateTime.Now.Subtract(start)).TotalMilliseconds
takes about 82s.
Any explaination as to why? I don't see a reason for that to happen. After all they both create objects how does creating a list differ from creating an array in this case. What is more the only element accessed is the head (or element 0) so there is no difference when searching for that element.
I am guessing it's allocation/GC (the array solution generates a few large objects, whereas the F# list generates tons of tiny ones), but I don't have a profiler handy to dig deeper now.
Seq.unfold is great if you have a well-defined sequence - e.g., the result of a method call. For more complex scenarios with 'yield return' you should prefer Sequence Computation Expressions. ([link:blogs.msdn.com])
Translated code (a little messily):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#light open System.Collections.Generic let primes = seq { // First prime yield 2 let sieve = new Dictionary<INT, int>() // Loop through all odd numbers < 1E3 for i in 3 .. 2 .. 1000 do // Check if its in our sieve (if not, its prime) let (found, value) = sieve.TryGetValue(i) let marker = if not found then i else value // Add to sieve let _ = let step = marker + marker let finalX = let initX = marker + step let rec incX x = if sieve.ContainsKey(x) then incX (x + step) else x incX initX sieve.Add(finalX, marker) if not found then yield i } printfn "%A" (Seq.take 100 primes)
Thanks a bunc! I wound up with this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
let Primes = seq { yield 2 let sieve = new Dictionary<int,int>() for i in 3 |> Seq.unfold (fun x -> Some(x, (x + 2))) do let (found, value) = sieve.TryGetValue(i) let marker = if found then value else i let _ = let step = marker + marker let rec Next x = if sieve.ContainsKey(x) then Next (x + step) else x let next = Next (marker + step) sieve.Add(next, marker) if not found then yield i }
The only thing I don't quite understand is why the yield needs to be the last thing in the seq and why "let _" is needed.
Hello.
Unfortunly, F# compiler does not allow to create recursive functions in sequence expressions, but we can create those into nested context (f.e. using "match ..." or "let _ = ...").
Also, we may not use "yield" into such nested contexts. So you code looks as it looks.
It's not necessary to use "yield" as last expression:
1 2 3 4 5 6
seq { let c = ref 1 for i in 1..1000 do yield i,if 1 = (i&&&1) then 0 else !c do incr c }
Topic tags
- f# × 3705
- websharper × 1897
- compiler × 286
- functional × 201
- ui next × 139
- c# × 121
- classes × 97
- web × 97
- .net × 84
- book × 84
- async × 76
- ui.next × 67
- bug × 54
- core × 49
- website × 49
- server × 45
- parallel × 43
- ui × 43
- enhancement × 41
- parsing × 41
- testing × 41
- trywebsharper × 41
- typescript × 37
- html × 35
- javascript × 35
- owin × 35
- asynchronous × 30
- monad × 28
- ocaml × 28
- tutorial × 27
- warp × 27
- haskell × 26
- sitelet × 25
- linq × 22
- workflows × 22
- wpf × 20
- fpish × 19
- introduction × 19
- silverlight × 19
- sitelets × 19
- monodevelop × 17
- rpc × 17
- suave × 17
- piglets × 16
- collections × 15
- feature request × 15
- jquery × 15
- templates × 15
- getting started × 14
- pipeline × 14
- kendoui × 13
- reactive × 12
- 4.1.0.171 × 11
- monads × 11
- opinion × 10
- 4.0.190.100-rc × 9
- deployment × 9
- fixed × 9
- formlets × 9
- in × 9
- json × 9
- plugin × 9
- proposal × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- highcharts × 8
- how-to × 8
- python × 8
- 4.1.1.175 × 7
- complexity × 7
- documentation × 7
- visual studio × 7
- 4.1.2.178 × 6
- lisp × 6
- real-world × 6
- released in 4.0.192.103-rc × 6
- remoting × 6
- resources × 6
- scala × 6
- websharper ui.next × 6
- workshop × 6
- xaml × 6
- 4.0.193.110 × 5
- 4.2.3.236 × 5
- aspnetmvc × 5
- authentication × 5
- azure × 5
- bootstrap × 5
- conference × 5
- dsl × 5
- formlet × 5
- java × 5
- list × 5
- metaprogramming × 5
- ml × 5
- released in Zafir.4.0.188.91-beta10 × 5
- sql × 5
- visualstudio × 5
- websharper.forms × 5
- zafir × 5
- 4.0.192.106 × 4
- 4.0.195.127 × 4
- 4.1.0.38 × 4
- 4.2.1.86 × 4
- 4.2.6.118 × 4
- css × 4
- example × 4
- extensions × 4
- fsi × 4
- fsx × 4
- html5 × 4
- jqueryui × 4
- lift × 4
- reflection × 4
- remote × 4
- rest × 4
- spa × 4
- teaching × 4
- template × 4
- websocket × 4
- wontfix × 4
- 4.0.196.147 × 3
- 4.1.0.34 × 3
- 4.1.6.207 × 3
- 4.2.1.223-beta × 3
- 4.2.11.258 × 3
- 4.2.4.114 × 3
- 4.2.4.247 × 3
- 4.2.5.115 × 3
- 4.2.6.253 × 3
- 4.2.9.256 × 3
- ajax × 3
- alt.net × 3
- aml × 3
- asp.net mvc × 3
- canvas × 3
- cloudsharper × 3
- compilation × 3
- database × 3
- erlang × 3
- events × 3
- extension × 3
- file upload × 3
- forums × 3
- inline × 3
- issue × 3
- kendo × 3
- macro × 3
- mono × 3
- msbuild × 3
- mvc × 3
- pattern × 3
- piglet × 3
- released in Zafir.4.0.187.90-beta10 × 3
- svg × 3
- type provider × 3
- view × 3
- 4.1.1.64 × 2
- 4.1.5.203 × 2
- 4.1.7.232 × 2
- 4.2.10.257 × 2
- 4.2.3.111 × 2
- 4.2.5.249 × 2
- android × 2
- asp.net × 2
- beginner × 2
- blog × 2
- chart × 2
- client × 2
- client server app × 2
- clojure × 2
- computation expressions × 2
- constructor × 2
- corporate × 2
- courses × 2
- cufp × 2
- d3 × 2
- debugging × 2
- direct × 2
- discriminated union × 2
- docs × 2
- elm × 2
- endpoint × 2
- endpoints × 2
- enterprise × 2
- entity framework × 2
- event × 2
- f# interactive × 2
- fable × 2
- flowlet × 2
- formdata × 2
- forms × 2
- fsc × 2
- google maps × 2
- hosting × 2
- http × 2
- https × 2
- iis 8.0 × 2
- install × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- jquery mobile × 2
- keynote × 2
- lens × 2
- lenses × 2
- linux × 2
- listmodel × 2
- mac × 2
- numeric × 2
- oauth × 2
- obfuscation × 2
- offline × 2
- oop × 2
- osx × 2
- packaging × 2
- pattern matching × 2
- performance × 2
- pipelines × 2
- q&a × 2
- quotation × 2
- reference × 2
- released in Zafir.4.0.185.88-beta10 × 2
- rx × 2
- script × 2
- security × 2
- self host × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- tutorials × 2
- type × 2
- url × 2
- var × 2
- websharper.charting × 2
- websharper4 × 2
- websockets × 2
- wig × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- 4.0.194.126 × 1
- 4.1.3.184 × 1
- 4.1.4.189 × 1
- 4.2.0.214-beta × 1
- 4.2.12.259 × 1
- 4.2.2.231-beta × 1
- 4.2.8.255 × 1
- Canvas Sample Example × 1
- DynamicStyle Animated Style × 1
- Fixed in 4.0.190.100-rc × 1
- Released in Zafir.UI.Next.4.0.169.79-beta10 × 1
- SvgDynamicAttribute × 1
- WebComponent × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- actor × 1
- addin × 1
- agents × 1
- aggregation × 1
- agile × 1
- alter session × 1
- animation × 1
- anonymous object × 1
- apache × 1
- api × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net core × 1
- asp.net integration × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- attributes × 1
- authorization × 1
- b-tree × 1
- back button × 1
- badimageformatexception × 1
- bash script × 1
- batching × 1
- binding-vars × 1
- bistro × 1
- body × 1
- bundle × 1
- camtasia studio × 1
- cas protocol × 1
- charts × 1
- clarity × 1
- class × 1
- cli × 1
- clipboard × 1
- clojurescript × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- color zones × 1
- combinator × 1
- combinators × 1
- compile × 1
- compile code on server × 1
- config × 1
- confirm × 1
- content × 1
- context × 1
- context.usersession × 1
- continuation-passing style × 1
- coords × 1
- cordova × 1
- cors × 1
- coursera × 1
- cross-domain × 1
- csla × 1
- current_schema × 1
- custom content × 1
- data × 1
- data grid × 1
- datetime × 1
- debug × 1
- declarative × 1
- delete × 1
- devexpress × 1
- dhtmlx × 1
- dictionary × 1
- directattribute × 1
- disqus × 1
- distance × 1
- do binding × 1
- doc elt ui.next upgrade × 1
- docker × 1
- dojo × 1
- dol × 1
- dom × 1
- domain × 1
- du × 1
- duf-101 × 1
- dynamic × 1
- eastern language × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- enums × 1
- error × 1
- etw × 1
- euclidean × 1
- eventhandlerlist × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- failed to translate × 1
- fake × 1
- fantomas × 1
- fear × 1
- float × 1
- form × 1
- form-data × 1
- forum × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- fsunit × 1
- function × 1
- functional style × 1
- game × 1
- games × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- getting-started × 1
- google × 1
- google.maps × 1
- grid × 1
- group × 1
- guide × 1
- hash × 1
- headers × 1
- hello world example × 1
- heroku × 1
- highchart × 1
- history × 1
- how to × 1
- html-templating × 1
- http405 × 1
- httpcontext × 1
- hubfs × 1
- i18n × 1
- ie 8 × 1
- if-doc × 1
- iis × 1
- image × 1
- images × 1
- inheritance × 1
- initialize × 1
- input × 1
- install "visual studio" × 1
- installer × 1
- int64 × 1
- interfaces × 1
- internet explorer × 1
- interop × 1
- interpreter × 1
- io × 1
- iobservable × 1
- ios × 1
- iot × 1
- ipad × 1
- isomorphic × 1
- javascript optimization × 1
- javascript semanticui resources × 1
- jquery-plugin × 1
- jquery-ui × 1
- jquery-ui-datepicker × 1
- js × 1
- kendo datasource × 1
- kendochart × 1
- kendoui compiler × 1
- knockout × 1
- l10n × 1
- learning × 1
- library × 1
- libs × 1
- license × 1
- licensing × 1
- lineserieszonescfg × 1
- local setting × 1
- localization × 1
- logging × 1
- loop × 1
- macros × 1
- mailboxprocessor × 1
- mapping × 1
- maps × 1
- markerclusterer × 1
- markup × 1
- marshal × 1
- math × 1
- mathjax × 1
- message × 1
- message passing × 1
- message-passing × 1
- meta × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- mix × 1
- mobile installation × 1
- mod_mono × 1
- modal × 1
- module × 1
- mouseevent × 1
- mouseposition × 1
- multidimensional × 1
- multiline × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- native × 1
- nested × 1
- nested loops × 1
- node × 1
- nunit × 1
- object relation mapper × 1
- object-oriented × 1
- om × 1
- onboarding × 1
- onclick × 1
- optimization × 1
- option × 1
- orm × 1
- os x × 1
- output-path × 1
- override × 1
- paper × 1
- parameter × 1
- persistence × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- post × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- privacy × 1
- private × 1
- profile × 1
- programming × 1
- project × 1
- project euler × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- proxy × 1
- ptvs × 1
- public × 1
- pure f# × 1
- purescript × 1
- qna × 1
- quant × 1
- query sitelet × 1
- question × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- reactjs × 1
- real-time × 1
- ref × 1
- region × 1
- released in 4.0.190.100-rc × 1
- reporting × 1
- responsive design × 1
- rest api × 1
- rest sitelet × 1
- restful × 1
- round table × 1
- router × 1
- routing × 1
- rpc reverseproxy × 1
- runtime × 1
- sales × 1
- sample × 1
- sampleapp × 1
- scriptcs × 1
- scripting × 1
- search × 1
- self hosted × 1
- semanticui × 1
- sequence × 1
- serialisation × 1
- service × 1
- session-state × 1
- sharepoint × 1
- signals × 1
- sitelet website × 1
- sitelet.protect × 1
- sitlets × 1
- slickgrid × 1
- source code × 1
- sqlentityconnection × 1
- ssl × 1
- standards × 1
- static content × 1
- stickynotes × 1
- streamreader × 1
- stress × 1
- strong name × 1
- structures × 1
- submitbutton × 1
- subscribe × 1
- svg example html5 websharper.ui.next × 1
- sweetalert × 1
- system.datetime × 1
- system.reflection.targetinvocationexception × 1
- table storage × 1
- targets × 1
- tdd × 1
- templates ui.next × 1
- templating × 1
- text parsing × 1
- three.js × 1
- time travel × 1
- tls × 1
- tooltip × 1
- tracing × 1
- tsunamiide × 1
- turkish × 1
- twitter-bootstrap × 1
- type erasure × 1
- type inference × 1
- type providers × 1
- type-providers × 1
- typeprovider × 1
- ui next forms × 1
- ui-next × 1
- ui.next jqueryui × 1
- ui.next charting × 1
- ui.next formlets × 1
- ui.next forms × 1
- ui.next suave visualstudio × 1
- ui.next templating × 1
- unicode × 1
- unittest client × 1
- upload × 1
- usersession × 1
- validation × 1
- vb × 1
- vb.net × 1
- vector × 1
- view.map × 1
- visal studio × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- vs2017 compiler zafir × 1
- vsix × 1
- web api × 1
- web-scraping × 1
- webapi × 1
- webcomponents × 1
- webforms × 1
- webgl × 1
- webrtc × 1
- webshaper × 1
- websharper async × 1
- websharper codemirror × 1
- websharper f# google × 1
- websharper forms × 1
- websharper reactive × 1
- websharper rpc × 1
- websharper sitelets routing × 1
- websharper warp × 1
- websharper-interface-generator × 1
- websharper.chartsjs × 1
- websharper.com × 1
- websharper.exe × 1
- websharper.owin × 1
- websharper.ui.next × 1
- websharper.ui.next jquery × 1
- websockets iis × 1
- why-websharper × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- www.grabbitmedia.com × 1
- xamarin × 1
- xml × 1
- yeoman × 1
- yield × 1
- zafir beta × 1
- zafir websharper4 × 1
- zarovizsga × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy |
Built with WebSharper |
I've created the following iterative prime sieve in C#
And now I wonder how do I "translate" it to F# I've found "Seq.unfold" and I guess that's half the answer but the other half I seem to not really get.
Any help greatly appriciated.