First I started with a happy little loop; it worked great on small numbers. I want to be able to run it for any positive Integer, but I figured I would work within the limits of a UInt32 until I got it going. Going through the loop to test all possible proper divisors of the number 24,000,000 took nearly 7 minutes, so 4 billion would take ...
Time to focus and get a grasp on using a Parallel.For loop. All this thread stuff is a little beyond me (not as much as a couple of days ago though) but I had success using a simple parallel.for loop. The same 24,000,000 took only about 1 minute to do its business. Pretty good, and much better than 7 minutes. Let's try it out on a real number. It didn't work: Out of Memory Exception Error. It happened sometimes when trying 5,000,000, sometimes 40,000,000, and in between the rest of the time.
So, I endeavored to split up the numbers I was processing into groups. I set the program to calculate all of the proper divisors of 4,200,000,000, then have it create arrays for segments thereof (1 to 5,000,000, then 5,000,001 to 10,000,000). If figured I was just trying to make it do too much at once. It helped a little, but not a lot. This tells me I took an ineffective approach to the problem. I added in lines to clear the array at the end of each segment, make the garbage collector collect, make the parallel range be nothing. This took it from running out of memory after 10 loops to 13.
I though of a) putting something in to monitor system resources and deal with running out of memory before it actually did run out of memory or B) forget about determining the proper divisors the old fashioned way and simply using the formula. With option a, I couldn't think of anything to do with such a warning if I had one, and with option b, I don't remember the formula, and I'm not entirely convinced I knew it when I actively studied math, and further, I wouldn't be surprised if the existence of such a formula is either unknown or one that could not possibly be calculated in Visual Basic.
In any event, maybe someone can give me a hint on a way to handle the evaporation of memory from trying to use a parallel.for loop 2 billion times.
Windows XP Pro SP3
Visual Basic 2010 Express SP1
Option Explicit On
Option Strict On
Option Infer On
Imports System.Collections.Concurrent Imports System.Threading.Tasks Imports System.Collections Imports System.Console Module Module1 Sub Main() CursorSize = 100 ForegroundColor = ConsoleColor.Green BackgroundColor = ConsoleColor.Black TreatControlCAsInput = False WindowHeight = CInt(Math.Truncate(LargestWindowHeight * 0.98)) WindowWidth = CInt(Math.Truncate(LargestWindowWidth * 0.98)) WindowTop = 0 WindowLeft = 0 ' ' ' Dim Big_Number As UInt32 = 4200000000 Dim Limit As Integer = 5000000 Dim Max_Number As Integer If Math.IEEERemainder(CDbl(Big_Number), 2) = 0 Then Max_Number = CInt(Big_Number / 2) ElseIf Math.IEEERemainder(CDbl(Big_Number), 2) = 1 Then Max_Number = CInt(Math.Truncate(Big_Number / 2)) + 1 End If Dim R As Integer Dim Q As Integer Q = CInt(Math.DivRem(Max_Number, Limit, R)) Dim NumberofSegments As Integer '= Q If R = 0 Then NumberofSegments = Q - 1 Else NumberofSegments = Q End If Dim Range_Segments(NumberofSegments, 1) As Integer For i = 0 To NumberofSegments Range_Segments(i, 0) = 1 + i * Limit If i < NumberofSegments Then Range_Segments(i, 1) = i * Limit + Limit ElseIf i = NumberofSegments Then Range_Segments(i, 1) = Max_Number End If Next Dim Source() As Integer Dim Remainder As Integer Dim Loop_Count As Integer = 0 Dim Output As New List(Of Integer) Dim Happy_Result_String As String Writeline() CursorVisible = False Try Loop_Start: Source = Enumerable.Range(Range_Segments(Loop_Count, 0), Range_Segments(Loop_Count, 1)).ToArray Dim RangePartitioner = Partitioner.Create(0, Source.Length) Parallel.ForEach(RangePartitioner, Sub(Range, LoopState) For i As Integer = Range.Item1 To Range.Item2 - 1 Remainder = CInt(Math.IEEERemainder(Big_Number, CDbl(Source(i)))) If Remainder = 0 Then Output.Add(Source(i)) End If Next End Sub) Array.Clear(Source, 0, UBound(Source)) Source = Nothing RangePartitioner = Nothing GC.Collect() Loop_Count = Loop_Count + 1 WriteLine("LOOPING ..." & Loop_Count) If Loop_Count <= NumberofSegments Then GoTo Loop_Start End If If Loop_Count > NumberofSegments Then GoTo Generate_Output End If Catch ex As OutOfMemoryException WriteLine() WriteLine("OUT OF MEMORY EXCEPTION AT:") WriteLine("Loop Count " & Loop_Count) WriteLine("CEASED CALCULATING. PRESS ANY KEY.") Happy_Result_String = Happy_Result_String & "OUT OF MEMORY EXCEPTION AT LOOP COUNT " & Loop_Count & "." & Chr(13) & Chr(10) End Try Generate_Output: Dim Happy_Result_Array = Output.ToArray() Array.Sort(Happy_Result_Array) For Each i In Happy_Result_Array Happy_Result_String = Happy_Result_String & i & Chr(13) & Chr(10) Next My.Computer.FileSystem.WriteAllText("F:\Partitioner_Output_Temp.txt", Happy_Result_String, True) WriteLine() WriteLine("Done. Press any key ...") Readkey(True) End Sub End Module
I also though of not using arrays at all and using lists exclusively, or perhaps dropping the use of a simple parallel.for and trying a more complex threading thing (it didn't seem appropriate though; I'm not doing a lot of things, I'm doing one thing a couple of billion times), or dusting off my old calculus book for a slightly more efficient means to get my answers, but I don't have it. I read something about manually allocating windows memory which was way over my head and then it said it was for 64 bit systems only anyway. I could just add more memory to my machine, but I can't really apply that as a solution (i.e. some method must be available to just do one thing a whole bunch of times no matter how little memory is available, it's not a complex calculation).
Any suggestions or guidance will be appreciated ...
Where did the flippin smiley face come from? It's like it's mocking me.
This post has been edited by AdamSpeight2008: 27 November 2011 - 06:51 PM
Reason for edit:: Disable emoticons: To remove Simley Face