none
Floor参与加减运算时出错 RRS feed

  • 问题

  • DECLARE @Price1 NUMERIC (38, 4),
            @Price2 NUMERIC (38, 1),
            @bfb    NUMERIC (38, 4)
    
    SELECT @Price1 = 0.7,
           @Price2 = 2.7;
    
    IF @Price1 <= 0.7
      BEGIN
          SELECT @bfb = Floor (@Price2) + 0.5;
          SELECT @bfb;
          --错误结果:3
    
          SELECT @bfb = Floor(2.7) + 0.5;
          SELECT @bfb;
          --正确结果:2.5
    
          SELECT @bfb = Floor (@Price2) - 0.5;
          SELECT @bfb;
          --错误结果:1
    
          SELECT @bfb = Floor(2.7) - 0.5;
          SELECT @bfb;
          --正确结果:1.5
      END 
    

    为什么在floor(变量)参与加减运算会出错?如果不直接参与运算就正确?

          SELECT @Price2 = Floor (@Price2) ;
          SELECT @bfb = Price2 + 0.5
          SELECT @bfb;
          --正确结果:2.5



    • 已编辑 SunYanLi 2013年11月26日 9:32
    2013年11月26日 7:53

答案

全部回复


  • 数据类型的问题

    Floor的结果,数据的精度不变,小数位变为0, 也就是 Foor(@Price2) 的结果类型为 numerc(38,0)

    38 已经是最大的精度,无法再扩充,与后面的0.5 代表的数据类型合并,这个合并的结果,会导致舍弃小数位,也就是说 Floow(@Price2) + 0.5 这个表达式的最终数据类型是 numeric(38,0)

    2.5 转换为 numeric(38,0) 的结果是3 (四舍五入),你如果+0.4 , 就会发现结果是 2

    • 已建议为答案 亂馬客 2013年11月26日 11:09
    • 已标记为答案 SunYanLi 2013年11月27日 0:20
    • 取消答案标记 SunYanLi 2013年11月27日 0:29
    • 取消建议作为答案 SunYanLi 2013年11月27日 0:30
    2013年11月26日 9:44
  • 你把变量的精度改小一点,这样表达式推算出的结果不会丢失小数位,这样出来的结果就是对的了
    2013年11月26日 9:45
  • 我也做了一下实验

    DECLARE @Price1 DECIMAL (18, 4),
            @Price2 DECIMAL (18, 4),
            @bfb    DECIMAL (18, 4)
    
    SELECT @Price1 = 0.7,
           @Price2 = 2.7
    
    IF @Price1 <= 0.7
      BEGIN
          SELECT @bfb = Floor (@Price2) + 0.5
          SELECT @bfb
    
    
          SELECT @bfb = Floor(2.7) + 0.5;
          SELECT @bfb;
        
    
          SELECT @bfb = Floor (@Price2) - 0.5;
          SELECT @bfb;
     
    
          SELECT @bfb = Floor(2.7) - 0.5;
          SELECT @bfb;
     
      END 

    用DECIMAL,结果都是正确的

    2013年11月26日 12:10

  • 数据类型的问题

    Floor的结果,数据的精度不变,小数位变为0, 也就是 Foor(@Price2) 的结果类型为 numerc(38,0)

    38 已经是最大的精度,无法再扩充,与后面的0.5 代表的数据类型合并,这个合并的结果,会导致舍弃小数位,也就是说 Floow(@Price2) + 0.5 这个表达式的最终数据类型是 numeric(38,0)

    2.5 转换为 numeric(38,0) 的结果是3 (四舍五入),你如果+0.4 , 就会发现结果是 2

          将DECLARE @Price2 NUMERIC (38, 1)改为DECLARE @Price2 NUMERIC (37, 1)的确Floor(@Price2) + 0.5后运算结果变成了2.5。按照我对你的说法理解之前的(38,1)的定义情况下乘除算法也应该取整的如(Floor(@Price2) * 0.5555)结果应该为1了,可是实际运算是Floor(@Price2) * 0.5555结果为为1.111。

          就是奇怪在这里加减(+、-)时他以@Price2的定义来出结果,而乘除(*、/)时他以@bfb的定义来出结果。

          我在Oracle中测试floor参与计算时就没有出现过这样的情况,当然我也知道他们不是1个算法,但是还是觉得Oracle的准确点,不管加减乘除(+、-、*、/)都是以bfb的定义来出结果。

    --Oracle中测试语句
    DECLARE Price1 NUMERIC (38, 4);
            Price2 NUMERIC (38, 1);
            bfb    NUMERIC (38, 4);
    BEGIN 
    
      Price1 := 0.7; Price2 := 2.7;
    
      IF Price1 <= 0.7 THEN
         bfb := Floor (Price2) + 0.5;
         dbms_output.put_line(bfb);
         --正确结果:2.5
         bfb := Floor(2.7) + 0.5;
         dbms_output.put_line(bfb);
         --正确结果:2.5
      END IF ;
    END;

    2013年11月27日 0:57
  • 你用DECIMAL精度不是最大,结果就是正确的。

    我最初定义的就是DECIMAL。

    你改为

    DECLARE @Price1 DECIMAL (38, 4),
            @Price2 DECIMAL (38, 1),
            @bfb    DECIMAL (36, 4)

    再看看运算结果就知道了。

    2013年11月27日 1:04
  • 的确是 
    2013年11月27日 1:14
  • +- 和 * / 的结果精度和小数位计算方式确实不同,这点之前倒真没有注意到

    联机帮助上有详细的说明:

    http://technet.microsoft.com/zh-cn/library/ms190476.aspx

    • 已标记为答案 SunYanLi 2013年11月27日 3:03
    2013年11月27日 1:36
  • 今天也找了一下资料

    http://msdn.microsoft.com/zh-cn/library/ms187746.aspx

    在 Transact-SQL 语句中,带有小数点的常量将自动转换为 numeric 数据值,而且使用必需的最小精度和小数位数。 例如,常量 12.345 将被转换为精度为 5,小数位数为 3 的 numeric 值。


    2013年11月28日 1:28
  • 不知道是不是变量和常量的差别
    2013年11月28日 1:33