浮点数据类型不适用于银行家四舍五入 - SQL Server 2008

时间:2014-03-05 17:39:04

标签: sql sql-server sql-server-2008 bankers-rounding

为了提供一些背景知识,我目前正致力于将Access数据库及其代码转换为SQL的项目。

在此过程中,我在SQL Server中将Double的Access数据类型更改为Float;我这样做是因为这些数据类型密切相关,因为我的数据库执行了大量的除法和乘法(我听说浮点数是最好的)。

转换数据库的另一个问题出现在Access使用银行家四舍五入而SQL没有;我出去找了两个UD银行家四舍五入的函数,两者都没有让一致的银行家围绕结果四舍五入。

当试图在浮点数上运行这些银行家舍入函数(包括减法和加法)时,这种不一致是否是我应该期待的?

以下是两个功能......

FUNCTION [dbo].[RB](@Val FLOAT, @Digits INT)
RETURNS FLOAT
AS
BEGIN
RETURN CASE WHEN ABS(@Val - ROUND(@Val, @Digits, 1)) * POWER(10, @Digits+1) = 5
           THEN ROUND(@Val, @Digits, CASE WHEN CONVERT(INT, ROUND(ABS(@Val) * 
                         POWER(10,@Digits), 0, 1)) % 2 = 1 THEN 0 ELSE 1 END)
           ELSE ROUND(@Val, @Digits)
       END
END


FUNCTION [dbo].[RoundBanker]
( @Amt   NUMERIC(38,16)
, @RoundToDecimal TINYINT
) 
RETURNS NUMERIC(38,16)
AS
BEGIN
DECLARE @RoundedAmt NUMERIC(38,16)
,   @WholeAmt       INT
,   @Decimal        TINYINT
,   @Ten            NUMERIC(38,16)
SET @Ten     = 10.0
SET @WholeAmt   = ROUND(@Amt,0, 1 )
SET @RoundedAmt = @Amt - @WholeAmt
SET @Decimal    = 16
WHILE @Decimal > @RoundToDecimal
BEGIN
SET @Decimal = @Decimal - 1 
IF 5 = ( ROUND(@RoundedAmt * POWER( @Ten, @Decimal + 1 ) ,0,1) - 
        (ROUND(@RoundedAmt * POWER( @Ten, @Decimal ) ,0,1) * 10) )
AND 0 = cast( ( ROUND(@RoundedAmt * POWER( @Ten, @Decimal ) ,0,1) - 
    (ROUND(@RoundedAmt * POWER( @Ten, @Decimal - 1 ) ,0,1) * 10) ) 
    AS INTEGER ) % 2
    SET @RoundedAmt = ROUND(@RoundedAmt,@Decimal, 1 )
ELSE 
    SET @RoundedAmt = ROUND(@RoundedAmt,@Decimal, 0 )
END
RETURN ( @RoundedAmt + @WholeAmt )
END

1 个答案:

答案 0 :(得分:1)

SQL Server ROUND()函数遵循IEEE标准754,并在使用float类型时使用“向上舍入”算法。如果需要更高的精度,请使用小数。不要使用浮动或真实。

请参阅此链接http://msdn.microsoft.com/en-us/library/ms187912.aspx