【发布时间】:2010-08-03 20:51:47
【问题描述】:
下面的代码用于计算两个城市之间的里程。在这种情况下,它是从缅因州雅茅斯到缅因州雅茅斯的距离 - 显然为零 - 这意味着雅茅斯 X 英里范围内的城市的结果应该包括雅茅斯本身。
问题是雅茅斯的纬度和经度似乎引起了某种浮点问题(我在其他城市没有看到这种情况):
DECLARE @fromlong FLOAT, @fromlat FLOAT, @tolong FLOAT, @tolat FLOAT, @test FLOAT
SET @fromlong = 43.8219
SET @fromlat = -70.1758
SET @tolong = 43.8219
SET @tolat = -70.1758
SET @test = SIN(@fromlong / ( 180 / PI() )) * SIN(@tolong / ( 180 / PI() )) + COS(@fromlong / ( 180 / PI() )) * COS(@tolong / ( 180 / PI() )) * COS(@fromlat / ( 180 / PI() ) - @tolat / ( 180 / PI() ))
PRINT @test /*** Displays "1" ***/
SELECT 3963.0 * ACOS(@test) /*** Displays "a domain error has occurred" ***/
首先,这是一个 SQL Server 错误吗?
其次,我该怎么做才能绕过它?我知道在上面的例子中我可以有一些IF @test > 1 的逻辑,但是这个例子是从嵌入在网络应用程序中的查询中提取的(不是我的选择),所以我需要修复查询,即修复计算,而不是求助如果可能的话到 TSQL,并且不扭曲任何其他返回值。有什么想法吗?
【问题讨论】:
-
如果需要精确值,为什么要浮动?
-
执行代码时是否应该出错?我没有得到一个只是0的结果。
-
很好 - 我回去查看了数据库,发现我使用的是 SSMS 2008,但数据库是 2005。我会相应地更改帖子。
-
我的机器上也没有出现错误(SQL2005 或 SQL2008 都没有)。如果我手动执行
SELECT ACOS(1.00000000000000000000001),我确实会收到该错误。那么你可以改变什么来解决这个问题?你能把它改成ACOS(CASE WHEN @test > 1 THEN 1 ELSE @test END)吗?能不能实现自己的ACOS函数? -
如果您进行计算,则永远不应该使用浮点数据类型,它们是估计值而不是精确值。这可能会导致您的问题,但如果不是,则仍然需要修复,因为浮点数可能会出现巨大的舍入问题。
标签: sql sql-server-2005 floating-point