July 22, 2010 at 3:22 pm
Cool, glad it worked well for you. Another optimization you might try is using the t-sql "returns null on null input" option, which allows sql server to short-circuit null handling without needing to even start running your clr code (you could then get rid of the explicit .IsNull checks in the clr code).
The diff between decimal and double is that double is a binary approximation of your values (based on ieee 854 std I believe), so you lose some scale accuracy. Decimal is an exact representation of your decimal values, related to the old binary coded decimal system. The important thing is that all the Math lib functions you're using deal in double data type, and those implicit conversions cost you. For a spatial data app I'd expect double to be "close enough" in most cases. If you need more accuracy than the double data type provides you'll probably need to use a different math library.
Mike C
July 22, 2010 at 3:41 pm
mzak (7/21/2010)
Hi Jeff. Here's the requested t-sql implementation.
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE Function [dbo].[Distance] (
@Lat1 as decimal(18, 6),
@Long1 as decimal(18, 6),
@Lat2 as decimal(18, 6),
@Long2 as decimal(18, 6))
Returns decimal(18, 6) With SchemaBinding
As
Begin
Declare @dLat1InRad as float(53)
Set @dLat1InRad = @Lat1 * ( PI() / 180.0 )
Declare @dLong1InRad as float(53)
Set @dLong1InRad = @Long1 * ( PI() / 180.0 )
Declare @dLat2InRad as float(53)
Set @dLat2InRad = @Lat2 * ( PI() / 180.0 )
Declare @dLong2InRad as float(53)
Set @dLong2InRad = @Long2 * ( PI() / 180.0 )
Declare @dLongitude as float(53)
Set @dLongitude = @dLong2InRad - @dLong1InRad
Declare @dLatitude as float(53)
Set @dLatitude = @dLat2InRad - @dLat1InRad
/* Intermediate result a. */
Declare @a as float(53)
Set @a = SQUARE( SIN( @dLatitude / 2.0 ) ) + COS( @dLat1InRad ) * COS( @dLat2InRad ) * SQUARE( SIN( @dLongitude / 2.0 ) )
/* Intermediate result c (great circle distance in Radians). */
Declare @C as real
Set @C = 2.0 * ATN2( SQRT( @a ), SQRT( 1.0 - @a ) )
Declare @EarthRadius as decimal(18, 6)
Set @EarthRadius = 3956.0 /* miles */
Declare @dDistance as decimal(18, 6)
Set @dDistance = @EarthRadius * @C
Return (@dDistance)
End
Thanks Matt. I've got some testing to do, now. 🙂 I'll be back.
--Jeff Moden
Change is inevitable... Change for the better is not.
July 22, 2010 at 3:45 pm
mzak (7/21/2010)
I figured Jeff would mention this shortly after I posted the requested T-SQL so I was anticipating it :-).
Nope... Wasn't even going to go there because I did understand the purpose of the article. That being said, looks like someone beat me to it anyway. 😉
--Jeff Moden
Change is inevitable... Change for the better is not.
July 22, 2010 at 5:00 pm
Mike C (7/22/2010)
Cool, glad it worked well for you. Another optimization you might try is using the t-sql "returns null on null input" option, which allows sql server to short-circuit null handling without needing to even start running your clr code (you could then get rid of the explicit .IsNull checks in the clr code).The diff between decimal and double is that double is a binary approximation of your values (based on ieee 854 std I believe), so you lose some scale accuracy. Decimal is an exact representation of your decimal values, related to the old binary coded decimal system. The important thing is that all the Math lib functions you're using deal in double data type, and those implicit conversions cost you. For a spatial data app I'd expect double to be "close enough" in most cases. If you need more accuracy than the double data type provides you'll probably need to use a different math library.
Mike C
Very cool. I was not aware of the "RETURNS NULL ON NULL INPUT" udf option.
Thanks again Mike.
Viewing 4 posts - 31 through 33 (of 33 total)
You must be logged in to reply to this topic. Login to reply