none
如何让sql server乘除法计算精准 RRS feed

  • 问题

  • 我在存储过程里面定义了很多decimal类型的变量,每次碰到乘除法,只要改变变量的小数位长度,得到的小数位结果也不同,有没有办法得到一个准确的结果

    我测试后发现是不是定义的时候长度小点,然后计算的时候用cast转换成大点的decimal类型是不是就解决了?

    2011年7月17日 4:11

答案

  • decimal型表达式 e1(精度为 p1,小数位数为 s1)和表达式 e2(精度为 p2,小数位数为 s2),
    它们运算结果的位数有如下算法:
    
    
    运算      结果精度              结果小数位数
    ----------------------------------------------------------------
    e1 + e2    max(s1, s2) + max(p1-s1, p2-s2) + 1      max(s1, s2)
    e1 - e2    max(s1, s2) + max(p1-s1, p2-s2) + 1      max(s1, s2)
    e1 * e2    p1 + p2 + 1                  s1 + s2
    e1 / e2    p1 - s1 + s2 + max(6, s1 + p2 + 1)      max(6, s1 + p2 + 1)
    e1 { UNION | EXCEPT | INTERSECT } e2  max(s1, s2) + max(p1-s1, p2-s2)    max(s1, s2)
    
    
    
    在本例中,当e1/e2时,结果小数位数取 max(6,s1+p2+1),但s1+p2+1>38,所以为了不截断整数部分,系统取了6.
    这就是为什么你把总精度设得那么高,小数部分反而总是6的原因。
    

    s1+s2 不超过38就应该不会被截断。
    2011年7月17日 4:59
    版主
  • 2011年7月17日 5:03
    版主

全部回复

  • decimal型表达式 e1(精度为 p1,小数位数为 s1)和表达式 e2(精度为 p2,小数位数为 s2),
    它们运算结果的位数有如下算法:
    
    
    运算      结果精度              结果小数位数
    ----------------------------------------------------------------
    e1 + e2    max(s1, s2) + max(p1-s1, p2-s2) + 1      max(s1, s2)
    e1 - e2    max(s1, s2) + max(p1-s1, p2-s2) + 1      max(s1, s2)
    e1 * e2    p1 + p2 + 1                  s1 + s2
    e1 / e2    p1 - s1 + s2 + max(6, s1 + p2 + 1)      max(6, s1 + p2 + 1)
    e1 { UNION | EXCEPT | INTERSECT } e2  max(s1, s2) + max(p1-s1, p2-s2)    max(s1, s2)
    
    
    
    在本例中,当e1/e2时,结果小数位数取 max(6,s1+p2+1),但s1+p2+1>38,所以为了不截断整数部分,系统取了6.
    这就是为什么你把总精度设得那么高,小数部分反而总是6的原因。
    

    s1+s2 不超过38就应该不会被截断。
    2011年7月17日 4:59
    版主
  • 2011年7月17日 5:03
    版主
  • 建议个p答案,我用来做BI计算的,循环计算了十几层,怎么定义算出来的跟excel里面计算出来都不一样,你给我定义一个循环调用计算的变量,最后算出来跟excel一样的那。

    小学生简单加减当然没问题了,你这种截断方法根本就不实用

    2011年7月30日 8:19
  • declare @temp_par4 as decimal(25,10)
    declare @dividend_par1 as decimal(19,2)
    declare @zero_par4 as decimal(25,15)
    declare @temp_par1 as decimal(25,10)

    set @temp_par1=559552119.9708648926
    set @dividend_par1=245373146.28
    set @zero_par4=0.070287068415871
    set @temp_par4=(@dividend_par1*@zero_par4/12+
        (0.315*@temp_par1-@dividend_par1*@zero_par4+@dividend_par1*@zero_par4/12)/(1-cast(1 as decimal(25,10))/12)/12)
        
    select @temp_par4

    得出的结果是16023537.9809830000

    而实际直接代入数字select 245373146.28*0.070287068415871/12+
        (0.315*559552119.9708648926-245373146.28*0.070287068415871+245373146.28*0.070287068415871/12)/(1-cast(1 as decimal(25,10))/12)/12

    得到:16023537.9809833278762

    都好像很懂一样,回的都很干脆直接,那我看你帮我解决多个变量计算小数精度问题,你看这个怎么弄

    2011年7月30日 10:22