- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm comparing the speed and accuracy of several coordinate transformation algorithms and find that the functionDATAN2D doubles the execution time ofthe whole program over and above that when using DATAN2. These two functions should really only differ by a multiplication operation (i.e. 57.3 deg/rad). Anybody have any ideas?
I use VS 2008, IVF 11.1.035, x64 platform,IDE environment.
This code illustrates the problem:
[bash] program main ! Compute longitude in equatorial xy plane. real*8 :: x, y, w, dw, LON, LonDeg, LonRad, t1, err, mx, t2 real*8,parameter :: delt = 1.d0/360.d0, rpd = datan(1.d0)/45.,& drad = delt * rpd, dpr = 1./rpd integer*4 :: i,j write (*,'("computing longitude")') mx = 0.d0 w = 6000000.d0 call cpu_time (t1) do i = 1, 10000 w = w + 10. ! increment by 10 m do j = 1, 32000 LonDeg = j * delt ! 1/360 deg to 88.9 degrees LonRad = j * drad ! same thing in radians x = w * dcos (LonRad) y = w * dsin (LonRad) ! call datan2 to recover Long. LON = dpr * datan2(y, x) ! this way takes 11.3 sec ! LON = datan2d (y, x) ! this way takes 22.7 sec <------ err = dabs (LON - LonDeg) ! error in degrees if (err > mx) mx = err ! max err, degrees enddo enddo call cpu_time(t2) write (*,'("max error:",f20.14," degrees")') mx write (*,'("time: ",f20.1," seconds")') t2-t1 end program main[/bash]
I use VS 2008, IVF 11.1.035, x64 platform,IDE environment.
This code illustrates the problem:
[bash] program main ! Compute longitude in equatorial xy plane. real*8 :: x, y, w, dw, LON, LonDeg, LonRad, t1, err, mx, t2 real*8,parameter :: delt = 1.d0/360.d0, rpd = datan(1.d0)/45.,& drad = delt * rpd, dpr = 1./rpd integer*4 :: i,j write (*,'("computing longitude")') mx = 0.d0 w = 6000000.d0 call cpu_time (t1) do i = 1, 10000 w = w + 10. ! increment by 10 m do j = 1, 32000 LonDeg = j * delt ! 1/360 deg to 88.9 degrees LonRad = j * drad ! same thing in radians x = w * dcos (LonRad) y = w * dsin (LonRad) ! call datan2 to recover Long. LON = dpr * datan2(y, x) ! this way takes 11.3 sec ! LON = datan2d (y, x) ! this way takes 22.7 sec <------ err = dabs (LON - LonDeg) ! error in degrees if (err > mx) mx = err ! max err, degrees enddo enddo call cpu_time(t2) write (*,'("max error:",f20.14," degrees")') mx write (*,'("time: ",f20.1," seconds")') t2-t1 end program main[/bash]
Link Copied
9 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It may not help, but why not use the generic names (eg SIN, COS, ATAN2, ABS). It is implied that they provide the maximum precision of the variable kind used.
Your conversion from Lat, Lon to X,Y could have a long way to go. The use of DATAN2D is the least of your problems.
John
Your conversion from Lat, Lon to X,Y could have a long way to go. The use of DATAN2D is the least of your problems.
John
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To John and anyone else, Idid apoorjob of describingmy situation. More details:
My project (in IDE environment)is to test 5 double-precision algorithms to convert geocentric (x, y, z) to geodetic (latitude, longitude, height). I have already determined accuracy and am now measuring how much CPU time is required to process a billion points. Optimization = fast and floating point model = fast. The times will indicate relative speed, hence will help decide which algorithm is best.
Here'smy problem. Common to all the algorithms is the one-line computation
lon = dpr * datan2 (y,x) or
lon = datan2d (y,x)
where dpr is degrees/radian. During the timing runs, I tried each of these equations in several of the algorithms and although accuracy was the same, total CPU time doubled when I used datan2d instead of datan2. I'm baffled. I thought the times would be the same.
To isolate the problem, I wrote the small program abovesimply tocompute longitude 320 million times. If the firstlongitude computationis commented out,the programtakes 23 seconds. If the second is commented out, it takes 11 seconds. So the problem remains, at least on my computer.
While performing the "paste" operation above, the exclamation mark in line 17 (column 1) disappeared and the"greater than"symbol became a "gt;" in line 20.
My project (in IDE environment)is to test 5 double-precision algorithms to convert geocentric (x, y, z) to geodetic (latitude, longitude, height). I have already determined accuracy and am now measuring how much CPU time is required to process a billion points. Optimization = fast and floating point model = fast. The times will indicate relative speed, hence will help decide which algorithm is best.
Here'smy problem. Common to all the algorithms is the one-line computation
lon = dpr * datan2 (y,x) or
lon = datan2d (y,x)
where dpr is degrees/radian. During the timing runs, I tried each of these equations in several of the algorithms and although accuracy was the same, total CPU time doubled when I used datan2d instead of datan2. I'm baffled. I thought the times would be the same.
To isolate the problem, I wrote the small program abovesimply tocompute longitude 320 million times. If the firstlongitude computationis commented out,the programtakes 23 seconds. If the second is commented out, it takes 11 seconds. So the problem remains, at least on my computer.
While performing the "paste" operation above, the exclamation mark in line 17 (column 1) disappeared and the"greater than"symbol became a "gt;" in line 20.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Perhapse DATAN2 is intrinsic or inlined whereas DATAN2D is a function call.
WRITE(*,*) "LOOK HERE"
LON=dpr*datan2(y,x)!thiswaytakes11.3sec
WRITE(*,*) LON
LON=datan2d(y,x)!thiswaytakes22.7sec<------
WRITE(*,*) LON
Modify your code to contain both functions and the write statements. Compile in Debug build with full optimizations. Place break point on "LOOK HERE". N.B. The write statements should still have valid breakpoint line number information. See if the code is inlined or via call.
Jim Dempsey
WRITE(*,*) "LOOK HERE"
LON=dpr*datan2(y,x)!thiswaytakes11.3sec
WRITE(*,*) LON
LON=datan2d(y,x)!thiswaytakes22.7sec<------
WRITE(*,*) LON
Modify your code to contain both functions and the write statements. Compile in Debug build with full optimizations. Place break point on "LOOK HERE". N.B. The write statements should still have valid breakpoint line number information. See if the code is inlined or via call.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The call to DATAN2 with the separate multiply calls an optimized ATAN2 routine directly. DATAN2D calls a library routine which in turn calls the optimized ATAN2, and does the multiply, though I see some extra code that seems to be protecting against some edge condition. I'm a bit surprised that DATAN2D takes twice as long, but there is an extra level of function call in there.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks toboth of youfor commenting.Will stickwith datan2.
Last quick question: Is itPOOR programming practice to let the compiler "promote" the constants to double precision, as I have done in the PARAMETER statement above? Iseem to keepdoing this to save a little space, to make it all look ateensy bit"cleaner", without all the "d"s -- because I know the compiler will take care of it.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The "modern" style is to define a parameter constant that uses SELECTED_REAL_KIND to determine the kind that has the precision you want, say, DP, and then use 1.0_DP. I know, even longer than D0, but it helps with portability. I would discourage you from allowing the compiler to promote types, and would also discourage you from using the specific intrinsic names such as DATAN. Use the generic names and properly typed arguments.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In addition to Steve's comment, a value that can not be represented exactly in single precision will
not get exactly the same approximate value if specified as single or double precision.
Try:
real(kind=sp) :: x = 1.2
real(kind=dp) :: y = 1.2_dp
write(*,*) x-y
(with obvious definitiions for sp and dp)
So it is better (IMHO) to be explicit about what you want.
Regards,
Arjen
not get exactly the same approximate value if specified as single or double precision.
Try:
real(kind=sp) :: x = 1.2
real(kind=dp) :: y = 1.2_dp
write(*,*) x-y
(with obvious definitiions for sp and dp)
So it is better (IMHO) to be explicit about what you want.
Regards,
Arjen
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for your tips, Steve and Arjen. I'm going to read up on them andput them into practiceright now (kind of precision, generic functions).
Don
Don
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You don't always need the long syntax and precision definition, as the abbreviated syntax can work in suitable cases, for example:
real*8, parameter :: one = 1
real*8 pi
pi = 4 * atan (one)
write (*,*) pi
end
Another important issue that is often lost in this debate about the difference between 1.2 and 1.2_dp, is what was the original intention of the supplied value of 1.2. Potentially it had an accuracy of 1.2 +/- .05, or quite possibly havebeen +/- .005 if a trailing zero was left out in the recording.
Unlike pi, 1.2 could represent, say, a 20% factor to an original estimate.
It is important to not loose focus on the accuracy of the measurement that can be provided to the numerical algorithm. Debates about thedifference between kind = 4, 8, or 16 often mask the real precision available.
John
real*8, parameter :: one = 1
real*8 pi
pi = 4 * atan (one)
write (*,*) pi
end
Another important issue that is often lost in this debate about the difference between 1.2 and 1.2_dp, is what was the original intention of the supplied value of 1.2. Potentially it had an accuracy of 1.2 +/- .05, or quite possibly havebeen +/- .005 if a trailing zero was left out in the recording.
Unlike pi, 1.2 could represent, say, a 20% factor to an original estimate.
It is important to not loose focus on the accuracy of the measurement that can be provided to the numerical algorithm. Debates about thedifference between kind = 4, 8, or 16 often mask the real precision available.
John
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page