【C#】Excel舍入函数Round、RoundUp、RoundDown的C#版

简介: 原文:【C#】Excel舍入函数Round、RoundUp、RoundDown的C#版本人在C#中进行小数舍入的时候常常会怀念Excel中的Round、RoundUp、RoundDown这几个函数,原因就是后者“接地气”,比较符合俺小老百姓的舍入要求,啥“银行家舍入法”就让银行家用去吧。
原文: 【C#】Excel舍入函数Round、RoundUp、RoundDown的C#版

本人在C#中进行小数舍入的时候常常会怀念Excel中的Round、RoundUp、RoundDown这几个函数,原因就是后者“接地气”,比较符合俺小老百姓的舍入要求,啥“银行家舍入法”就让银行家用去吧。今儿有空,就把它实现了一下,先温习一下这几个Excel函数的功能:

Round(value, digits)

将value按四舍五入法进行舍入,保留digits位小数;当digits为负时,在小数点左侧进行舍入;当value为负时,表现与正数完全相反。

举例:Round(3.145, 2) = 3.15;Round(-3.145, 2) = -3.15;Round(3145, -2) = 3100

RoundUp(value, digits)

按远离 0 的方向,将value向上舍入,保留digits位小数;当digits为负时,在小数点左侧进行舍入

举例:RoundUp(3.111, 2) = 3.12;RoundUp(-3.111, 2) = -3.12;RoundUp(3111, -2) = 3200

RoundDown(value, digits)

按靠近 0 的方向,将value向下舍入,保留digits位小数;当digits为负时,在小数点左侧进行舍入

举例:RoundDown(3.145, 2) = 3.14;RoundDown(-3.145, 2) = -3.14;RoundDown(3145, -2) = 3100

实现原理:

- 对于RoundUp和RoundDown,由于decimal或Math类的Ceiling和Floor方法(下称C/F)只能取整,所以先根据要保留的位数,乘除得到可供C/F方法发挥的新值,然后就可以利用C/F得到舍入后的值,再乘/除回去,得到最终结果。此法市面常见。

举例:1.114向上保留2位,首先1.114x100得到111.4,再用C(111.4)得到112,然后112 / 100,最终得到1.12

问题:由于要先对原值进行乘除,所以对于接近Max/Min、或精度过高的原值,这一步就会造成溢出,所以Up和Down不能应对特别大的值,但日常应用相信没问题。

- 对于RoundEx方法,则直接封装decimal.Round(decimal, MidpointRounding.AwayFromZero)得到结果。

实现说明:

- 以扩展方法提供,兼容常规方法调用方式(废话)。即可以3.145M.RoundEx(2),也可以MathEx.RoundEx(3.145M, 2)

- 每个方法以decimal和double两种类型提供重载,共6个方法

- 以decimal类型为基础进行实现,double版只是重用+类型转换。之所以不对double进行实现,不是因为偷懒,而是因为浮点运算容易扯蛋,如555.55x100=55554.999999999993。关于浮点运算的不可靠性,可参看:http://www.cnblogs.com/ethancai/articles/1237012.html

- 四舍五入函数命名为RoundEx是因为decimal类已经存在一个叫Round的静态方法,如果不错开,将不能以扩展方式3M.Round()进行调用。而且虽然.net在命名上具有极大的包容度,但我认为还是尽量避开FCL命名的好,无谓去“享受”这种自由度

- 几个方法之所以都要先判断一下保留位数,而没有直接使用10的digits次方进行运算,是想尽量沿用decimal类型的原生方法,减少没必要的数学运算。咱追求的不是极简的代码,而是性能。当然,没测试过~鸡蛋飞来中...

废话了一堆,上代码:

/// <summary>
/// 数学类扩展方法
/// </summary>
public static class MathEx
{
    /// <summary>
    /// 远离 0 向上舍入
    /// </summary>
    public static decimal RoundUp(this decimal value, sbyte digits)
    {
        if (digits == 0)
        {
            return (value >= 0 ? decimal.Ceiling(value) : decimal.Floor(value));
        }

        decimal multiple = Convert.ToDecimal(Math.Pow(10, digits));
        return (value >= 0 ? decimal.Ceiling(value * multiple) : decimal.Floor(value * multiple)) / multiple;
    }

    /// <summary>
    /// 靠近 0 向下舍入
    /// </summary>
    public static decimal RoundDown(this decimal value, sbyte digits)
    {
        if (digits == 0)
        {
            return (value >= 0 ? decimal.Floor(value) : decimal.Ceiling(value));
        }

        decimal multiple = Convert.ToDecimal(Math.Pow(10, digits));
        return (value >= 0 ? decimal.Floor(value * multiple) : decimal.Ceiling(value * multiple)) / multiple;
    }

    /// <summary>
    /// 四舍五入
    /// </summary>
    public static decimal RoundEx(this decimal value, sbyte digits)
    {
        if (digits >= 0)
        {
            return decimal.Round(value, digits, MidpointRounding.AwayFromZero);
        }

        decimal multiple = Convert.ToDecimal(Math.Pow(10, -digits));
        return decimal.Round(value / multiple, MidpointRounding.AwayFromZero) * multiple;
    }

    /// <summary>
    /// 远离 0 向上舍入
    /// </summary>
    public static double RoundUp(this double value, sbyte digits)
    {
        return decimal.ToDouble(Convert.ToDecimal(value).RoundUp(digits));
    }

    /// <summary>
    /// 靠近 0 向下舍入
    /// </summary>
    public static double RoundDown(this double value, sbyte digits)
    {
        return decimal.ToDouble(Convert.ToDecimal(value).RoundDown(digits));
    }

    /// <summary>
    /// 四舍五入
    /// </summary>
    public static double RoundEx(this double value, sbyte digits)
    {
        return decimal.ToDouble(Convert.ToDecimal(value).RoundEx(digits));
    }
}

- 文毕 -

目录
相关文章
|
10月前
|
C#
C# 中关于补位的写法 PadLeft,PadRight 函数
C# 中的 `PadLeft` 和 `PadRight` 是 String 类提供的用于字符串补位的实用方法。`PadLeft` 在字符串左侧填充指定字符,使其达到指定长度;`PadRight` 则在右侧填充。两者通过检查原字符串长度,计算需填充字符数,并创建新字符数组完成操作。时间复杂度为 O(n),适用于简单补位场景,但在大量操作时需注意性能影响。示例代码展示了如何使用这两个方法进行补位操作。
|
数据库 C语言 索引
必知的技术知识:excel函数
必知的技术知识:excel函数
238 0
|
SQL C# 数据库
EPPlus库的安装和使用 C# 中 Excel的导入和导出
本文介绍了如何使用EPPlus库在C#中实现Excel的导入和导出功能。首先,通过NuGet包管理器安装EPPlus库,然后提供了将DataGridView数据导出到Excel的步骤和代码示例,包括将DataGridView转换为DataTable和使用EPPlus将DataTable导出为Excel文件。接着,介绍了如何将Excel数据导入到数据库中,包括读取Excel文件、解析数据、执行SQL插入操作。
EPPlus库的安装和使用 C# 中 Excel的导入和导出
|
C# Python
使用wxpython开发跨平台桌面应用,对wxpython控件实现类似C#扩展函数处理的探究
【10月更文挑战第30天】使用 `wxPython` 开发跨平台桌面应用时,可以通过创建辅助类来模拟 C# 扩展函数的功能。具体步骤包括:1. 创建辅助类 `WxWidgetHelpers`;2. 在该类中定义静态方法,如 `set_button_color`;3. 在应用中调用这些方法。这种方法提高了代码的可读性和可维护性,无需修改 `wxPython` 库即可为控件添加自定义功能。但需要注意显式调用方法和避免命名冲突。
137 1
excel 百分位函数 学习
excel 百分位函数 学习
556 1
|
文字识别 C# Python
使用C#将几个Excel文件合并去重分类
使用C#将几个Excel文件合并去重分类
203 3
|
数据安全/隐私保护
杨老师课堂之Excel VBA 程序开发第八讲使用工作表函数
杨老师课堂之Excel VBA 程序开发第八讲使用工作表函数
171 1
【C#】C#读写Excel文件
【C#】C#读写Excel文件
515 1
|
开发框架 算法 .NET
C#使用MiniExcel导入导出数据到Excel/CSV文件
C#使用MiniExcel导入导出数据到Excel/CSV文件
480 0
|
存储 API C#
C# 实现格式化文本导入到Excel
C# 实现格式化文本导入到Excel