General > Off Topic

This two codes do the same thing...

(1/3) > >>

Botsareus:
(had to tone it down a little to make it more presentable :p)

Numsgil, correct me if I am wrong on this:


--- Code: ---'calculates difference between two angles (A)
Private Function angle_compare(ByVal ang1 As Double, ByVal ang2 As Double) As Double
'A dot B = |A| * |B| * cos(angle between them)
'(A dot B) / (|A| * |B|) = cos(angle between them)
'-(A cross B) / (|A| * |B|) = sin(angle between them)
Ay = Sin(ang1 / 180 * pi)
Ax = Cos(ang1 / 180 * pi)
By = Sin(ang2 / 180 * pi)
Bx = Cos(ang2 / 180 * pi)
mydotproduct = Ax * Bx + Ay * By
resultingcos = mydotproduct
mycrossproduct = Ax * By - Ay * Bx
resultingsin = -mycrossproduct

k = angle(resultingcos, resultingsin, 0, 0) / pi * 180
If k > 180 Then k = k - 360
angle_compare = k
End Function

'calculates difference between two angles (B)
Public Function AngDiff(ByVal a1 As Double, ByVal a2 As Double) As Double
a1 = a1 / 180 * pi
a2 = a2 / 180 * pi
  Dim r As Double
  r = a1 - a2
  If r > pi Then
    r = -(2 * pi - r)
  End If
  If r < -pi Then
    r = r + 2 * pi
  End If
  AngDiff = r * 180 / pi
End Function

--- End code ---

I am actually preferring version B for several reasons:

1.) Smaller
2.) Less CPU intensive
3.) It is already build in (I need this for a function I am planning in DarwinBots)
4.) It does not make sense for me to use Sin, Cos and ArcTangent if I can avoid them.

Don't get me wrong, it is still a very cool formula. And, probably still useful in other applications.

Numsgil:
It's weird that the first function is converting from angles to vectors and then back, yeah.  As to whether they do the same thing or not... What happens in the second one if one of the inputs is > 4pi?  Also, why are you converting to radians, and then converting back to degrees at the end?

Botsareus:

--- Quote ---What happens in the second one if one of the inputs is > 4pi?
--- End quote ---

Well, it is always used together with 'angnorm' :


--- Code: ---' normalizes angle in 0,2pi
Public Function angnorm(ByVal an As Single) As Single
  While an < 0
    an = an + 2 * PI
  Wend
  While an > 2 * PI
    an = an - 2 * PI
  Wend
  angnorm = an
End Function

--- End code ---


--- Quote ---Also, why are you converting to radians, and then converting back to degrees at the end?
--- End quote ---

Ah, no that's for my personal experiments. I guess I learned trig originally using degrees and just prefer that over radians, this has nothing to do with DarwinBots but I do use this in my personal projects. -I did not want to bother modify the version B  function too much. Just corrected it for the values my system uses in my personal experiment and checked it against version (A) I was very surprised when I found out it worked perfectly, here is the full source, maybe when you have time you can check it out:


--- Code: ---Private Const pi = 3.14159265358979
Dim ang1 As Double
Dim ang2 As Double

Dim a As Double

Dim i As Byte

Private Sub Form_Load()
ang2 = 180
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
sx = ScaleWidth / 2
sy = ScaleHeight / 2
cang1 = ang1 / 180 * pi
cang2 = ang2 / 180 * pi
If Sqr((X - Cos(cang1 + pi) * sx / 1.5 - sx) ^ 2 + (Y - Sin(cang1 + pi) * sy / 1.5 - sy) ^ 2) < 200 Then
i = 1
ElseIf Sqr((X - Cos(cang2 + pi) * sx / 1.5 - sx) ^ 2 + (Y - Sin(cang2 + pi) * sy / 1.5 - sy) ^ 2) < 200 Then
i = 2
End If
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
sx = ScaleWidth / 2
sy = ScaleHeight / 2
If i = 1 Then
ang1 = angle(sx, sy, X, Y) * 180 / pi
End If
If i = 2 Then
ang2 = angle(sx, sy, X, Y) * 180 / pi
End If
End Sub

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
i = 0
End Sub

Private Sub Timer1_Timer() 'enabled = true; interval = 1
Dim cang1 As Double
Dim cang2 As Double

cang1 = ang1 / 180 * pi
cang2 = ang2 / 180 * pi
Cls
sx = ScaleWidth / 2
sy = ScaleHeight / 2
'screen
Me.Circle (sx, sy), sx / 1.5, vbWhite
'line1
Me.Line (sx, sy)-(sx - Cos(cang1) * sx / 1.5, sy - Sin(cang1) * sy / 1.5), vbBlue
Me.Circle (sx - Cos(cang1) * sx / 1.5, sy - Sin(cang1) * sy / 1.5), 200, vbBlue
'line2
Me.Line (sx, sy)-(sx - Cos(cang2) * sx / 1.5, sy - Sin(cang2) * sy / 1.5), vbGreen
Me.Circle (sx - Cos(cang2) * sx / 1.5, sy - Sin(cang2) * sy / 1.5), 200, vbGreen

a = (a + 1) Mod 50
res = AngDiff(ang1, ang2)


'line3
lang = cang2 + a / 50 * res / 180 * pi



Me.Line (sx, sy)-(sx - Cos(lang) * sx / 1.5, sy - Sin(lang) * sy / 1.5), vbRed
End Sub

'calculates difference between two angles
Private Function angle_compare(ByVal ang1 As Double, ByVal ang2 As Double) As Double
'A dot B = |A| * |B| * cos(angle between them)
'(A dot B) / (|A| * |B|) = cos(angle between them)
'-(A cross B) / (|A| * |B|) = sin(angle between them)
Ay = Sin(ang1 / 180 * pi)
Ax = Cos(ang1 / 180 * pi)
By = Sin(ang2 / 180 * pi)
Bx = Cos(ang2 / 180 * pi)
mydotproduct = Ax * Bx + Ay * By
resultingcos = mydotproduct
mycrossproduct = Ax * By - Ay * Bx
resultingsin = -mycrossproduct

k = angle(resultingcos, resultingsin, 0, 0) / pi * 180
If k > 180 Then k = k - 360
angle_compare = k
End Function

'calculates difference between two angles
Public Function AngDiff(ByVal a1 As Double, ByVal a2 As Double) As Double
a1 = a1 / 180 * pi
a2 = a2 / 180 * pi
  Dim r As Double
  r = a1 - a2
  If r > pi Then
    r = -(2 * pi - r)
  End If
  If r < -pi Then
    r = r + 2 * pi
  End If
  AngDiff = r * 180 / pi
End Function


Private Function angle(ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single) As Single
        Dim an As Single
        Dim dx As Single
        Dim dy As Single
        dx = x1 - x2
        dy = y1 - y2
        If dx = 0 Then
            'an = 0
            an = pi / 2
            If dy < 0 Then an = pi / 2 * 3
        Else
            an = Math.Atn(dy / dx)
            If dx < 0 Then
                an = an + pi
            End If
        End If
        If an < 0 Then an = an + pi * 2
        angle = an
End Function

--- End code ---

Botsareus:
Just ran another experiment. 'angnorm' is slowing down version B considerably. So, unless you have angles that perfectly fit in the 0 to 2 pi range, you are better of using the first function I described. Although I would have never thought how computationally inexpensive converting to vectors and then back to angles is, Numsgil is still the god of video game mathematics.  :Headbang: I rest my case.

P.S.

Now I feel a little dumb because I should of ran a test like this in the first place...

Botsareus:
Numsgil, please help me figure this out, it is not making much sense:

So, my input is


--- Code: ---ang1 = (Rnd * 1200 - 400) / 180 * pi 'never converted back to degrees

--- End code ---

The function


--- Code: ---...
e = e + 1
Caption = e & "AngDiff" & angnorm(ang1)
DoEvents
Loop

--- End code ---

is faster then


--- Code: ---...
e = e + 1
Caption = e & "AngComp" & angle(Cos(ang1), Sin(ang1), 0, 0)
DoEvents
Loop

--- End code ---

Meanwhile, the function


--- Code: ---...
e = e + 1
Caption = e & "AngComp2" & angle_compare(ang1, ang2)
DoEvents
Loop

--- End code ---

is faster then


--- Code: ---...
e = e + 1
Caption = e & "AngDiff2" & AngDiff(angnorm(ang1), angnorm(ang2))
DoEvents
Loop
--- End code ---

See post above to figure out what 'AngDiff' 'angnorm' 'angle_compare' and 'angle' do

My qustion to you is: Where is my performance loss? Because as far as I can tell


--- Code: ---angle(Cos(ang1), Sin(ang1), 0, 0)
--- End code ---

should be faster then


--- Code: ---angnorm(ang1)
--- End code ---


Navigation

[0] Message Index

[#] Next page

Go to full version