5

据我所知,当舍入数为 5 时,根据数学舍入应该如下工作。

2.435 => 2.44 (Round Up, if rounding to digit(3) is odd number)
2.445 => 2.44 (Round Down, if rounding to digit(4) is even number)

如果我们做总结一切都很好,

2.435 + 2.445 =  4.88
2.44 + 2.44 = 4.88 

我很确定在.Net中也可以像这样进行舍入。

但在 SQL Server 中,5 总是向上取整,根据数学计算是不正确的。

SELECT round(2.345, 2)  = 2.35
SELECT round(2.335, 2) => 2.34

这导致四舍五入值的总和有 1 美分的差异。

2.345 + 2.335 = 4.68
2.35 + 2.34 = 4.69 => which is not correct

我已经尝试过使用小数和货币数据类型。

难道我做错了什么?有解决办法吗?

4

3 回答 3

6

您正在寻找银行家的舍入- 这是 C# 中的默认舍入,但不是 SQL Server ROUND() 的工作方式。

请参阅为什么 Sql Server 2000 上的 TSQL 会不一致地舍入小数?以及http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/sql-server-rounding-methodshttp://www.chrispoulter.com/blog/post/rounding-decimals-using-net -and-t-sql

于 2013-09-17T10:38:54.117 回答
6

如果您确实想在 SQL Server 中使用银行家四舍五入...

CREATE FUNCTION BankersRounding(@value decimal(36,11), @significantDigits INT)        
RETURNS MONEY        
AS        
BEGIN        
    -- if value = 12.345 and signficantDigits = 2...        

    -- base = 1000        
    declare @base int = power(10, @significantDigits + 1)        


    -- roundingValue = 12345        
    declare @roundingValue decimal(36,11) = floor(abs(@value) * @base)        
    -- roundingDigit = 5        
    declare @roundingDigit int = @roundingValue % 10        

    -- significantValue = 1234        
    declare @significantValue decimal(36,11) = floor(@roundingValue / 10)        
    -- lastSignificantDigit = 4        
    declare @lastSignificantDigit int = @significantValue % 10        


    -- awayFromZero = 12.35        
    declare @awayFromZero money = (@significantValue + 1) / (@base / 10)        
    -- towardsZero = 12.34        
    declare @towardsZero money = @significantValue / (@base / 10)        

    -- negative values handled slightly different        
    if @value < 0        
    begin        
        -- awayFromZero = -12.35        
        set @awayFromZero = ((-1 * @significantValue) - 1) / (@base / 10)        
        -- towardsZero = -12.34        
        set @towardsZero = (-1 * @significantValue) / (@base / 10)        
    end        

    -- default to towards zero (i.e. assume thousandths digit is 0-4)        
    declare @rv money = @towardsZero        
    if @roundingDigit > 5        
        set @rv = @awayFromZero  -- 5-9 goes away from 0        
    else if @roundingDigit = 5         
    begin        
        -- 5 goes to nearest even number (towards zero if even, away from zero if odd)        
        set @rv = case when @lastSignificantDigit % 2 = 0 then @towardsZero else @awayFromZero end        
    end        

    return @rv        

end        
于 2014-03-12T15:11:33.737 回答
5

数学上在 5 处四舍五入是正确的,也是基础数学中最常用的四舍五入类型。其他类型的四舍五入也是有效的,但不是基础数学,但更常用于某些领域,因为 0.5 通常是一个有争议的数字。

您所谓的数学舍入实际上是银行家舍入,这是金融业务中使用的舍入类型。

于 2013-09-17T10:38:10.387 回答