C# Round源码

在日常开发中经常遇到四舍五入的情况比如 Math.Round(1.25, 1),首先我们要知道这里的Round 其实是银行家算法,具体可以参考Round() 四舍五入 js银行家算法 那么C#是如何实现的了,我们来看看decimal的round实现如下:

复制代码
  
       [System.Security.SecuritySafeCritical]  // auto-generated
        public static Decimal Round(Decimal d, int decimals)
        {
            FCallRound (ref d, decimals);
            return d;
        }

        public static Decimal Round(Decimal d, MidpointRounding mode) {
            return Round(d, 0, mode);
        }
  
  
        [System.Security.SecuritySafeCritical]  // auto-generated
        public static Decimal Round(Decimal d, int decimals, MidpointRounding mode) {
            if ((decimals < 0) || (decimals > 28))
                throw new ArgumentOutOfRangeException("decimals", Environment.GetResourceString("ArgumentOutOfRange_DecimalRound"));
            if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) {            
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnumValue", mode, "MidpointRounding"), "mode");
            }
            Contract.EndContractBlock();

            if (mode == MidpointRounding.ToEven) {
                FCallRound (ref d, decimals);
            }
            else {
                InternalRoundFromZero(ref d, decimals);
            }
            return d;
        }

        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern void FCallRound(ref Decimal d, int decimals);
        

  // Does an in-place round the specified number of digits, rounding mid-point values
        // away from zero
        private static void InternalRoundFromZero(ref Decimal d, int decimalCount) {
            Int32 scale = (d.flags & ScaleMask) >> ScaleShift;
            Int32 scaleDifference = scale - decimalCount;
            if (scaleDifference <= 0) {
                return;
            }
            // Divide the value by 10^scaleDifference
            UInt32 lastRemainder;
            UInt32 lastDivisor;
            do {
                Int32 diffChunk = (scaleDifference > MaxInt32Scale) ? MaxInt32Scale : scaleDifference;
                lastDivisor = Powers10[diffChunk];
                lastRemainder = InternalDivRemUInt32(ref d, lastDivisor);
                scaleDifference -= diffChunk;
            } while (scaleDifference > 0);
            
            // Round away from zero at the mid point
            if (lastRemainder >= (lastDivisor >> 1)) {
                InternalAddUInt32RawUnchecked(ref d, 1);
            }
            
            // the scale becomes the desired decimal count
            d.flags = ((decimalCount << ScaleShift) & ScaleMask) | (d.flags & SignMask);
        }
复制代码

所以我们如果想要四舍五入 那么方法必须穿入MidpointRounding 参数,调用托管代码;不传这是银行家算法调用非托管代码,从性能的角度讲应该竟可能调用托管代码。所以除非有要求,尽力调用托管代码吧。

 

posted on   dz45693  阅读(1576)  评论(0编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示