算法:四舍六入五成双 ,保留三位有效数字

     在实际的生产制造统计中,会有精度丢失的情况. 倘若按照 我们平常所用的 四舍五入,(1234舍掉, 56789 进位)

这样会使整体数据偏大(理论模型).

      为了使整体数据保持平均,生产制造有这样一种计算方式,也就是 四舍六入无成双.

 

例如保留3位有效数字:  

  1.235 => 1.235

  1.2354=>1.235 (0.0004舍掉)

  1.2355=>1.236 (0.0005前面是奇数,进位)

  1.2365=>1.236 (0.0005前面是偶数,舍弃)

C# 代码如下

/// <summary>
/// 格式化 Decimal 数字  用于有效计算
/// </summary>
/// <param name="ori"></param>
/// <returns></returns>
/// <remarks></remarks>
public static decimal FormatDecimal(decimal ori)
{
    if (ori == 0) {
        return 0;
    }

    decimal num = ori;
    decimal result = 0m;
    int zoome = 1;

    //小于100的数, 数字放大 10的  指数倍,直到 数字 大于等于100

    while (num < 100) {
        num = num * 10;
        zoome = zoome * 10;
    }

    int int1 = Math.Floor(num);
    decimal d1 = Math.Floor(num) + 0.5;

    // 四舍六入
    // 5 看尾数 和奇偶

    if (num > d1) {
        //如果 5后面有尾数, 进位
        result = int1 + 1;
    } else if (num == d1) {
        // 看前一位  偶数不变,奇数 +1
        if (int1 % 2 == 0) {
            result = int1;
        } else {
            result = int1 + 1;
        }
    } else {
        //整数
        result = int1;
    }

    //有效数字取到以后 缩小到原来的数量级
    result = result / zoome;
    return result;
}

/// <summary>
/// 格式化字符串显示 Decimal 数字
/// </summary>
/// <param name="ori"></param>
/// <returns></returns>
/// <remarks></remarks>
public static string ShowDecimal(decimal ori)
{

    if (ori == 0) {
        return "0";
    }
    //首先  得到 格式化之后的数据, 有效数字
    ori = FormatDecimal(ori);

    string strNum = "";
    decimal num = ori;

    //判断是不是 3位及3位以上数字 直接取整数部分

    if (num >= 100) {
        strNum = num.ToString();
    } else if (num > 0) {
        // 三位数以下, 涉及到 取小数点
        string s = num.ToString();
        // 没有小数点, 先补齐 小数点位数
        if (s.Contains(".")) {
            s = s + "00";
        } else {
            s = s + ".00";
        }


        // 遍历取 3位有效数字
        char[] array = s.ToCharArray();
        int start = 0;

        for (int i = 0; i <= array.Length - 1; i++) {
            if (start == 3) {
                break; // TODO: might not be correct. Was : Exit For
            }

            if (array[i] == ".") {
                strNum = strNum + ".";
            } else {
                int t = int.Parse(array[i]);
                if (t > 0) {
                    start = start + 1;
                    strNum = strNum + t;
                } else if (t == 0) {
                    if (start > 0) {
                        start = start + 1;
                        strNum = strNum + t;
                    } else {
                        strNum = strNum + t;
                    }
                }
            }
        }
    }


    return strNum;

}
View Code

 

SQL 代码如下

create function [dbo].[func_formatDecimal](@wgt decimal(16,6)) 

  returns numeric(16,3) 

  as 

   begin 

      if @wgt = 0 

        begin 

          return 0 

        end   

      declare @num  decimal(16,6),@result numeric(16,3),@zoome integer 

      set  @num = @wgt 

      set @result = 0 

      set @zoome = 1 

      --小于100的数, 数字放大 10 的倍数 

      while @num<100 

       begin 

          set @num = @num * 10 

          set @zoome = @zoome * 10 

       end 

     declare @int1 integer,@d1 numeric(16,1)   

     set @int1 =  floor(@num) 

     set @d1 = floor(@num)+0.5 

      --四舍六入 

      --5 看尾数和奇偶 

      if @num>@d1  

        begin 

          set @result = @int1+1 

        end 

      else if @num =@d1 

        begin 

         --看前一位 偶数不变,奇数+1 

            if @int1 % 2 = 0 

              set @result = @int1 

            else  

              set @result = @int1+1  

        end   

       else 

         set @result = @int1  

     set @result = @result / @zoome 

     return(@result) 

   end 
View Code

 

  本人才疏学浅,如果你有更好的方法,欢迎留言讨论.

 

posted @ 2014-10-24 16:54  兴想事成  阅读(1049)  评论(0编辑  收藏  举报