Results 1 to 17 of 17

Thread: [VB.NET 4.0] Can you speed up this function? :)

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Nov 2005
    Posts
    183

    [VB.NET 4.0] Can you speed up this function? :)

    I have some code for calculating a "polytrope" (a good model for some types of star). I was reading some optimisation threads on this forum today and it made me curious enough to try to make it faster. It was already probably the most efficient program I'd made since it was my first truly multithreaded application (that actually benefited hugely from it).

    Moving "Math.PI" into a constant so it's only called once didn't make any measurable difference in the time taken. However, replacing two occurrences of "r ^ 2" with a new variable initialised to "r ^ 2", which was then used twice, improved the speed of the code by 35%!

    I don't actually need this code as it's from an old program but I'm just curious to see if there are any other efficiency improvements one could make?

    P.S. This is running in 64-bit mode so I don't think changing any of the Doubles into Singles will improve speed.

    VB Code:
    1. Public Const G As Double = 0.00000000006674     'gravitational constant
    2.     Public Const Pi As Double = Math.PI             'Pi
    3.  
    4.     Public Function CalculatePolytrope(ByVal n As Double, ByVal StepSize As Double, ByVal Rho As Double, ByVal P As Double) As Double()
    5.  
    6.         Dim K As Double = P / (Rho ^ ((n + 1) / n)) 'constant of polytrope model
    7.         Dim m As Double = 0                         'mass
    8.         Dim r As Double = 0 - StepSize              'radius
    9.         Dim dP_dr As Double                         'dP/dr
    10.         Dim dm_dr As Double                         'dm/dr
    11.         Dim rSquared As Double                      'r^2
    12.  
    13.         'Process loop until Rho or P are equal to (or less than) zero:
    14.         Do
    15.             'Increment r
    16.             r += StepSize
    17.  
    18.             'This prevents dP/dr and dm/dr becoming NaN ("not a number") when r = 0
    19.             If r = 0 Then
    20.                 dP_dr = 0
    21.                 dm_dr = 0
    22.             Else
    23.                 rSquared = r ^ 2
    24.                 dP_dr = -(G * m * Rho) / rSquared
    25.                 dm_dr = 4 * Pi * Rho * rSquared
    26.             End If
    27.  
    28.             'Calculate new mass and pressure
    29.             m += StepSize * dm_dr
    30.             P += StepSize * dP_dr
    31.  
    32.             'This prevents square rooting a minus number, which would make Rho NaN ("not a number")
    33.             If P > 0 Then
    34.                 Rho = (P / K) ^ (n / (n + 1))
    35.             Else
    36.                 Rho = 0
    37.             End If
    38.         Loop Until Rho <= 0 OrElse P <= 0
    39.  
    40.         'Create an array of doubles to hold our final M and R then return them to the calling subroutine.
    41.         Dim Results() As Double = {m, r}
    42.         Return Results
    43.  
    44.     End Function
    Last edited by DragonQ; Feb 2nd, 2011 at 09:08 PM.

  2. #2
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: [VB.NET 4.0] Can you speed up this function? :)

    A minor improvement would be to alter lines 19 to 30, because m and p will only be altered if r is not 0. As such, you could use this to get the same behaviour:
    Code:
                If r <> 0 Then
                    rSquared = r ^ 2
                    dP_dr = -(G * m * Rho) / rSquared
                    dm_dr = 4 * Pi * Rho * rSquared
                    'Calculate new mass and pressure
                    m += StepSize * dm_dr
                    P += StepSize * dP_dr
                End If
    ...and maybe even eliminate dP_dr and dm_dr.


    While storing Pi didn't do you much good, storing 4*Pi (which is what you actually use) is likely to be better.


    As n doesn't change inside the loop, it would be a good idea to store (n / (n + 1)) to a variable too.


    Due to the conditions/values used in lines 32 to 38, you could simplify that a bit too, eg:
    Code:
                'This prevents square rooting a minus number, which would make Rho NaN ("not a number")
                If P <= 0 Then Exit Do
                Rho = (P / K) ^ (n / (n + 1))
            Loop Until Rho <= 0

  3. #3

    Thread Starter
    Addicted Member
    Join Date
    Nov 2005
    Posts
    183

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Thanks for the suggestions! I've read that using >= or <= is slower than > or < so I've tried to avoid using them in this new version. By setting Rho to -1 instead of 0 if "P > 0" is false, I can change the loop condition to "Rho < 0", which should be a bit quicker.

    Below is what I have now. This version is 4% faster (averaged over 5 tests) than the version I posted above (which was in turn 35% faster than the code I started with):

    VB Code:
    1. '
    2.     Public Const G As Double = 0.00000000006674             'gravitational constant
    3.     Public Const Pi_x4 As Double = Math.PI * 4              '4 Pi
    4.  
    5.     Public Function CalculatePolytrope(ByVal n As Double, ByVal StepSize As Double, ByVal Rho As Double, ByVal P As Double) As Double()
    6.  
    7.         Dim PolytropeIndex As Double = n / (n + 1)          'n / (n + 1)
    8.         Dim K As Double = P / (Rho ^ (1 / PolytropeIndex))  'constant of polytrope model
    9.         Dim m As Double = 0                                 'mass
    10.         Dim r As Double = 0 - StepSize                      'radius
    11.         Dim dP_dr As Double                                 'dP/dr
    12.         Dim dm_dr As Double                                 'dm/dr
    13.         Dim rSquared As Double                              'r^2
    14.  
    15.         'Process loop until Rho or P are equal to (or less than) zero:
    16.         Do
    17.             'Increment r
    18.             r += StepSize
    19.  
    20.             'This prevents dP/dr and dm/dr becoming NaN ("not a number") when r = 0
    21.             If r = 0 Then
    22.                 dP_dr = 0
    23.                 dm_dr = 0
    24.             Else
    25.                 rSquared = r ^ 2
    26.                 dP_dr = -(G * m * Rho) / rSquared
    27.                 dm_dr = Pi_x4 * Rho * rSquared
    28.             End If
    29.  
    30.             'Calculate new mass and pressure
    31.             m += StepSize * dm_dr
    32.             P += StepSize * dP_dr
    33.  
    34.             'This prevents square rooting a minus number, which would make Rho NaN ("not a number")
    35.             If P > 0 Then
    36.                 Rho = (P / K) ^ PolytropeIndex
    37.             Else
    38.                 Rho = -1
    39.             End If
    40.         Loop Until Rho < 0
    41.  
    42.         'Create an array of doubles to hold our final M and R then return them to the calling subroutine.
    43.         Dim Results() As Double = {m, r}
    44.         Return Results
    45.  
    46.     End Function

    Here's a couple of other things I've tried without measurable effect:
    • Making the "G" variable negative so it doesn't need to be made negative each time dP_dr is calculated.
    • Moving the negative sign from the dP_dr calculation to the "P += ..." line (change to "P -= ...")

    And here's some more things I've tried that all make the code slower (bizzarly):
    • Changing the "If r = 0" condition to "If r <> 0" or "If r > 0" or "If Not r = 0" and swapping the If/Else sections around.
    • Changing "Rho = -1" to "Exit Do".
    • Putting the "m += ..." and "P += ..." lines inside the Else section of the "If r = 0" condition.
    • Getting rid of dP_dr and dm_dr in conjunction with the previous change.
    • Commenting out the unneeded "dP_dr = 0" and "dm_dr = 0" lines.

    Strange...

  4. #4
    Frenzied Member
    Join Date
    Dec 2007
    Posts
    1,072

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Instead of initializing a variable to return, you can return directly:
    Code:
    Return New Double() {m, r}
    Instead of
    Code:
     rSquared = r ^ 2
    try
    Code:
    r=r*r
    (ya I know it's minor)

  5. #5

    Thread Starter
    Addicted Member
    Join Date
    Nov 2005
    Posts
    183

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Woah...replacing "r ^ 2" with "r * r" improved speed by a further 69&#37;! Ridiculous. That means compared to what I started with, the code is now ~140% faster (~2.4x).

    EDIT: After some further trial-and-error, the fastest I can get so far is a ~165% improvement (2.65x). Here's the code for this:

    VB Code:
    1. '
    2.     Public Const G As Double = 0.00000000006674             'gravitational constant
    3.     Public Const Pi_x4 As Double = Math.PI * 4              '4π
    4.  
    5.     Public Function CalculatePolytrope(ByVal n As Double, ByVal StepSize As Double, ByVal Rho As Double, ByVal P As Double) As Double()
    6.        
    7.         Dim PolytropeIndex As Double = n / (n + 1)          'n / (n + 1)
    8.         Dim K As Double = P / (Rho ^ (1 / PolytropeIndex))  'constant of polytrope model
    9.         Dim m As Double = 0                                 'mass
    10.         Dim r As Double = 0 - StepSize                      'radius
    11.         Dim dP_dr As Double                                 'dP/dr (excluding Rho term)
    12.         Dim rSquared As Double                              'r^2
    13.         Dim StepSize_x_Rho As Double                        'StepSize x Rho
    14.  
    15.         'Process loop until Rho or P are equal to (or less than) zero:
    16.         Do
    17.             'Increment r
    18.             r += StepSize
    19.  
    20.             'This prevents dP/dr and dm/dr becoming NaN ("not a number") when r = 0
    21.             If r > 0 Then
    22.                 rSquared = r * r
    23.                 dP_dr = (G * m) / rSquared
    24.                 StepSize_x_Rho = StepSize * Rho
    25.  
    26.                 'Calculate new mass and pressure
    27.                 m += (StepSize_x_Rho * Pi_x4 * rSquared)
    28.                 P -= (StepSize_x_Rho * dP_dr)
    29.             End If
    30.  
    31.             'This prevents square rooting a minus number, which would make Rho NaN ("not a number")
    32.             If P > 0 Then
    33.                 Rho = (P / K) ^ PolytropeIndex
    34.             Else
    35.                 Rho = -1
    36.             End If
    37.         Loop Until Rho < 0
    38.  
    39.         'Create an array of doubles to hold our final M and R then return them to the calling subroutine.
    40.         Return {m, r}
    41.  
    42.     End Function
    Last edited by DragonQ; Feb 4th, 2011 at 09:59 PM.

  6. #6
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Is it possible for the the Rho value to ever be 0 or less from the calculation? If so are you sure that your loop exit condition is apt?

    In terms of speed I suspect the quickest code for it would be Loop Until Rho = 0 , but that could lead to a change in behaviour.

  7. #7

    Thread Starter
    Addicted Member
    Join Date
    Nov 2005
    Posts
    183

    Re: [VB.NET 4.0] Can you speed up this function? :)

    That is true, the condition could be changed to "Rho = 0" without a change in behaviour. It doesn't improve speed though, unfortunately.

    The original program managed to perform the calculation with a range of input values that I originally made the code for in 414 s (5000 runs, 8 threads at a time, i7 920 @ 3.8 GHz). The current version (post 5) does it in 154 s.

  8. #8
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: [VB.NET 4.0] Can you speed up this function? :)

    I don't know if this does anything for speed, but stop initializing variables to 0, and replace 0 - stepSize with just -stepSize, it looks better

    At the end instead of setting Rho to -1 you could use GoTo and maybe take out the loop, I wonder how that would work?

    For conciseness, take out all those unnecessary parentheses (like around Stepsize_x_Rho * Pi_x4 * rSquared and G * m and Stepsize_x_Rho * dp_dr).

  9. #9
    PowerPoster Nightwalker83's Avatar
    Join Date
    Dec 2001
    Location
    Adelaide, Australia
    Posts
    13,344

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Quote Originally Posted by minitech View Post
    Actually, r ^ 2 = r * r. Sorry.
    Yeah, I tried explaining it but I wrote the equation incorrectly thinking r*r*r = r ^2 when it was meant to be r *r = r ^2. I deleted my original post because it was too long-winded and confusing. Although, the above still doesn't seem to explain why r*r would be faster than r^2?

    Edit:

    Maybe the fact that DragonQ had rSquared dimmed as double had something to do with it.
    Last edited by Nightwalker83; Mar 15th, 2011 at 09:16 PM. Reason: Adding more!
    when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
    If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
    https://get.cryptobrowser.site/30/4111672

  10. #10
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: [VB.NET 4.0] Can you speed up this function? :)

    ^ is an operator that implicitly uses Doubles on both sides and performs a multitude of completely unnecessary operations to accomodate decimal and negative powers. Multiplication, being a fundamental binary operation, is much faster.

  11. #11
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: [VB.NET 4.0] Can you speed up this function? :)

    @Dragon - post sample data in the following format please

    Code:
            Dim smplData() As Double = New Double() {n, StepSize, Rho, P, M_answer, R_answer, _
                                                     n, StepSize, Rho, P, M_answer, R_answer, _
                                                     n, StepSize, Rho, P, M_answer, R_answer}
    replacing the variables with the actual values. Two or three sets should be good, more if you want.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  12. #12

    Thread Starter
    Addicted Member
    Join Date
    Nov 2005
    Posts
    183

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Code:
    Dim smplData() As Double = New Double() {1, 1000, 4.6E+1, 4.4E+10, 2.005282E+028, 6.995690E+008, _
                                                     1, 1000, 4.6E+3, 4.4E+12, 2.005340E+027, 6.995200E+007, _
                                                     1, 1000, 4.6E+5, 4.4E+14, 2.005925E+026, 6.991000E+006}

  13. #13
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Maybe a little better, but it is hard to tell...

    Code:
        Private Sub Button2_Click(sender As System.Object, _
                                  e As System.EventArgs) Handles Button2.Click
    
            Dim sd() As Double = New Double() {1, 1000, 46.0, 44000000000.0, 2.0052816957994727E+28, 699569000.0, _
                                               1, 1000, 4600.0, 4400000000000.0, 2.0053401856028196E+27, 69952000.0, _
                                               1, 1000, 460000.0, 440000000000000.0, 2.0059251372079435E+26, 6991000.0}
            Dim stpw As New Stopwatch
            stpw.Start()
            For y As Integer = 1 To 20
                For x As Integer = 0 To sd.Length - 1 Step 6
                    Dim ans() As Double = CalculatePolytrope(sd(x), sd(x + 1), sd(x + 2), sd(x + 3))
                    If ans(0) = sd(x + 4) AndAlso ans(1) = sd(x + 5) Then
                        'Debug.WriteLine("m={0} r={1}", ans(0), ans(1))
                    Else
                        Stop
                    End If
                Next
            Next y
            stpw.Stop()
            'Debug.WriteLine(stpw.ElapsedMilliseconds.ToString("n0"))
            TextBox1.Text = stpw.ElapsedMilliseconds.ToString("n0")
        End Sub
    
        Public Const G As Double = 0.00000000006674#            'gravitational constant
        Public Const Pi_x4 As Double = Math.PI * 4              '4π
    
        Public Function CalculatePolytrope(ByVal n As Double, _
                                           ByVal StepSize As Double, _
                                           ByVal Rho As Double, _
                                           ByVal P As Double) As Double()
    
            Dim PolytropeIndex As Double = n / (n + 1)          'n / (n + 1)
            Dim K As Double = P / (Rho ^ (1 / PolytropeIndex))  'constant of polytrope model
            Dim m As Double                                'mass
            Dim r As Double = -StepSize                      'radius
            Dim dP_dr As Double                                  'dP/dr (excluding Rho term)
            Dim rSquared As Double                                'r^2
            Dim StepSize_x_Rho As Double                         'StepSize x Rho
    
            'Process loop until Rho or P are equal to (or less than) zero:
            Do
                'Increment r
                r += StepSize
    
                'This prevents dP/dr and dm/dr becoming NaN ("not a number") when r = 0
                If r > 0 Then
                    rSquared = r * r
                    dP_dr = (G * m) / rSquared
                    StepSize_x_Rho = StepSize * Rho
    
                    'Calculate new mass and pressure
                    m += (StepSize_x_Rho * Pi_x4 * rSquared)
                    P -= (StepSize_x_Rho * dP_dr)
                    If P <= 0 Then Exit Do
                End If
    
                Rho = (P / K) ^ PolytropeIndex
            Loop Until Rho < 0
    
            'Create an array of doubles to hold our final M and R then return them to the calling subroutine.
            Return {m, r}
    
        End Function
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  14. #14

    Thread Starter
    Addicted Member
    Join Date
    Nov 2005
    Posts
    183

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Nice try but it's no quicker.

    It's probably a good idea to give you the settings used for my benchmark which gives me 4.10-4.15 seconds with my current code (the slowest of the 9 original calculations the program was intended for):

    vb Code:
    1. '
    2. Dim StartTime as DateTime = DateTime.Now
    3.  
    4. Dim Results As Double() = CalculatePolytrope(1, 1000, 46.0, 440000000000000.0)
    5.  
    6. Dim TimeElapsed As TimeSpan = DateTime.Now.Subtract(StartTime)
    7. txtTimeElapsed.Text = Format((TimeElapsed.TotalMilliseconds / 1000), "##0.00").ToString & " s"

  15. #15
    PowerPoster
    Join Date
    Nov 2002
    Location
    Manila
    Posts
    7,629

    Re: [VB.NET 4.0] Can you speed up this function? :)

    (a/b)^x same as a^x / b^x

    K ^ PolytropeIndex is a constant

  16. #16

    Thread Starter
    Addicted Member
    Join Date
    Nov 2005
    Posts
    183

    Re: [VB.NET 4.0] Can you speed up this function? :)

    Good suggestion but again that idea ends up slowing the program down (4.25-4.30 s vs 4.10-4.15 s).

  17. #17
    PowerPoster
    Join Date
    Nov 2002
    Location
    Manila
    Posts
    7,629

    Re: [VB.NET 4.0] Can you speed up this function? :)

    I see.

    I'm curious though why you didn't use a formula based on dM/dr since you are after mass anyway. isn't it possible? Maybe the algorithm and computation would be more efficient with that approach.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width