none
[팁] C# 소수점 반올림 관련 보조 라이브러리 RRS feed

  • 일반 토론

  • 응용프로그램 작성 도중 C#의 소수점 반올림 관련 코드에서 몇몇 자주 사용되는 기능들을 보완하는 코드를 작성하여 올려봅니다. 이 코드는 http://www.latiumsoftware.com/en/delphi/00033.php 의 코드를 바탕으로 작성된 것입니다.

    namespace System
    {
        // Original Source: http://www.latiumsoftware.com/en/delphi/00033.php
        public static class MathExtension
        {
            public static int Sign(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return Math.Sign(x);
            }

            public static int Sign(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return Math.Sign(x);
            }

            public static int Integer(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return (int)Math.Truncate(x);
            }

            public static int Integer(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return (int)Math.Truncate(x);
            }

            public static decimal Fraction(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return x - Math.Truncate(x);
            }

            public static double Fraction(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return x - Math.Truncate(x);
            }

            public static decimal RoundUp(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return Integer(x) + Sign(Fraction(x));
            }

            public static double RoundUp(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return Integer(x) + Sign(Fraction(x));
            }

            public static decimal RoundDown(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return Integer(x);
            }

            public static double RoundDown(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return Integer(x);
            }

            public static decimal Round(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return Integer(x) + Integer(Fraction(x) * 2m);
            }

            public static double Round(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return Integer(x) + Integer(Fraction(x) * 2d);
            }

            public static decimal Fix(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                if (x >= 0m || Fraction(x) == 0m)
                    return Integer(x);
                else
                    return Integer(x) - 1;
            }

            public static double Fix(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                if (x >= 0d || Fraction(x) == 0d)
                    return Integer(x);
                else
                    return Integer(x) - 1;
            }

            public static decimal RoundDownFix(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return Fix(x);
            }

            public static double RoundDownFix(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return Fix(x);
            }

            public static int Absolute(
    #if CS3
                this
    #endif // CS3
                int x)
            {
                return Math.Abs(x);
            }

            public static decimal RoundUpFix(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return Fix(x) + Absolute(Sign(Fraction(x)));
            }

            public static double RoundUpFix(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return Fix(x) + Absolute(Sign(Fraction(x)));
            }

            public static decimal RoundFix(
    #if CS3
                this
    #endif // CS3
                decimal x)
            {
                return Fix(x + 0.5m);
            }

            public static double RoundFix(
    #if CS3
                this
    #endif // CS3
                double x)
            {
                return Fix(x + 0.5d);
            }

            public static decimal RoundTo(
    #if CS3
                this
    #endif // CS3
                decimal x, int d)
            {
                decimal n = (decimal)Math.Pow(10, d);
                x *= n;
                return (Integer(x) + Integer(Fraction(x) * 2m)) / n;
            }

            public static double RoundTo(
    #if CS3
                this
    #endif // CS3
                double x, int d)
            {
                double n = Math.Pow(10, d);
                x *= n;
                return (Integer(x) + Integer(Fraction(x) * 2d)) / n;
            }
        }
    }

    사용 예시는 다음과 같습니다.

    using System;

    namespace ConsoleApplication1
    {
        public static class Program
        {
            [STAThread]
            public static void Main(string[] args)
            {
    #if CS3
                Console.WriteLine("{0}", (3.3m).RoundUp() == 4m);
                Console.WriteLine("{0}", (-3.3m).RoundUp() == -4m);
                Console.WriteLine("{0}", (3.7m).RoundDown() == 3m);
                Console.WriteLine("{0}", (-3.7m).RoundDown() == -3m);
                Console.WriteLine("{0}", (3.5m).Round() == 4m);
                Console.WriteLine("{0}", (-3.5m).Round() == -4m);
                Console.WriteLine("{0}", (3.1m).Round() == 3m);
                Console.WriteLine("{0}", (-3.1m).Round() == -3m);
                Console.WriteLine("{0}", (3.7m).Integer() == 3);
                Console.WriteLine("{0}", (-3.7m).Integer() == -3);
                Console.WriteLine("{0}", (3.7m).Fix() == 3m);
                Console.WriteLine("{0}", (-3.7m).Fix() == -4m);
                Console.WriteLine("{0}", (3.7m).RoundDownFix() == 3m);
                Console.WriteLine("{0}", (-3.7m).RoundDownFix() == -4m);
                Console.WriteLine("{0}", (3.1m).RoundDownFix() == 3m);
                Console.WriteLine("{0}", (-3.1m).RoundDownFix() == -4m);
                Console.WriteLine("{0}", (3.1m).RoundUpFix() == 4m);
                Console.WriteLine("{0}", (-3.7m).RoundUpFix() == -3m);
                Console.WriteLine("{0}", (3.5m).RoundFix() == 4m);
                Console.WriteLine("{0}", (-3.5m).RoundFix() == -3m);
                Console.WriteLine("{0}", (123.456m).RoundTo(0) == 123.00m);
                Console.WriteLine("{0}", (123.456m).RoundTo(2) == 123.46m);
                Console.WriteLine("{0}", (123456m).RoundTo(-3) == 123000m);

                Console.WriteLine("{0}", (3.3d).RoundUp() == 4d);
                Console.WriteLine("{0}", (-3.3d).RoundUp() == -4d);
                Console.WriteLine("{0}", (3.7d).RoundDown() == 3d);
                Console.WriteLine("{0}", (-3.7d).RoundDown() == -3d);
                Console.WriteLine("{0}", (3.5d).Round() == 4d);
                Console.WriteLine("{0}", (-3.5d).Round() == -4d);
                Console.WriteLine("{0}", (3.1d).Round() == 3d);
                Console.WriteLine("{0}", (-3.1d).Round() == -3d);
                Console.WriteLine("{0}", (3.7d).Integer() == 3);
                Console.WriteLine("{0}", (-3.7d).Integer() == -3);
                Console.WriteLine("{0}", (3.7d).Fix() == 3d);
                Console.WriteLine("{0}", (-3.7d).Fix() == -4d);
                Console.WriteLine("{0}", (3.7d).RoundDownFix() == 3d);
                Console.WriteLine("{0}", (-3.7d).RoundDownFix() == -4d);
                Console.WriteLine("{0}", (3.1d).RoundDownFix() == 3d);
                Console.WriteLine("{0}", (-3.1d).RoundDownFix() == -4d);
                Console.WriteLine("{0}", (3.1d).RoundUpFix() == 4d);
                Console.WriteLine("{0}", (-3.7d).RoundUpFix() == -3d);
                Console.WriteLine("{0}", (3.5d).RoundFix() == 4d);
                Console.WriteLine("{0}", (-3.5d).RoundFix() == -3d);
                Console.WriteLine("{0}", (123.456d).RoundTo(0) == 123.00d);
                Console.WriteLine("{0}", (123.456d).RoundTo(2) == 123.46d);
                Console.WriteLine("{0}", (123456d).RoundTo(-3) == 123000d);
    #else // !CS3
                Console.WriteLine("{0}", MathExtension.RoundUp(3.3m) == 4m);
                Console.WriteLine("{0}", MathExtension.RoundUp(-3.3m) == -4m);
                Console.WriteLine("{0}", MathExtension.RoundDown(3.7m) == 3m);
                Console.WriteLine("{0}", MathExtension.RoundDown(-3.7m) == -3m);
                Console.WriteLine("{0}", MathExtension.Round(3.5m) == 4m);
                Console.WriteLine("{0}", MathExtension.Round(-3.5m) == -4m);
                Console.WriteLine("{0}", MathExtension.Round(3.1m) == 3m);
                Console.WriteLine("{0}", MathExtension.Round(-3.1m) == -3m);
                Console.WriteLine("{0}", MathExtension.Integer(3.7m) == 3);
                Console.WriteLine("{0}", MathExtension.Integer(-3.7m) == -3);
                Console.WriteLine("{0}", MathExtension.Fix(3.7m) == 3);
                Console.WriteLine("{0}", MathExtension.Fix(-3.7m) == -4);
                Console.WriteLine("{0}", MathExtension.RoundDownFix(3.7m) == 3m);
                Console.WriteLine("{0}", MathExtension.RoundDownFix(-3.7m) == -4m);
                Console.WriteLine("{0}", MathExtension.RoundDownFix(3.1m) == 3m);
                Console.WriteLine("{0}", MathExtension.RoundDownFix(-3.1m) == -4m);
                Console.WriteLine("{0}", MathExtension.RoundUpFix(3.1m) == 4m);
                Console.WriteLine("{0}", MathExtension.RoundUpFix(-3.7m) == -3m);
                Console.WriteLine("{0}", MathExtension.RoundFix(3.5m) == 4m);
                Console.WriteLine("{0}", MathExtension.RoundFix(-3.5m) == -3m);
                Console.WriteLine("{0}", MathExtension.RoundTo(123.456m, 0) == 123.00m);
                Console.WriteLine("{0}", MathExtension.RoundTo(123.456m, 2) == 123.46m);
                Console.WriteLine("{0}", MathExtension.RoundTo(123456m, -3) == 123000m);

                Console.WriteLine("{0}", MathExtension.RoundUp(3.3d) == 4d);
                Console.WriteLine("{0}", MathExtension.RoundUp(-3.3d) == -4d);
                Console.WriteLine("{0}", MathExtension.RoundDown(3.7d) == 3d);
                Console.WriteLine("{0}", MathExtension.RoundDown(-3.7d) == -3d);
                Console.WriteLine("{0}", MathExtension.Round(3.5d) == 4d);
                Console.WriteLine("{0}", MathExtension.Round(-3.5d) == -4d);
                Console.WriteLine("{0}", MathExtension.Round(3.1d) == 3d);
                Console.WriteLine("{0}", MathExtension.Round(-3.1d) == -3d);
                Console.WriteLine("{0}", MathExtension.Integer(3.7d) == 3);
                Console.WriteLine("{0}", MathExtension.Integer(-3.7d) == -3);
                Console.WriteLine("{0}", MathExtension.Fix(3.7d) == 3);
                Console.WriteLine("{0}", MathExtension.Fix(-3.7d) == -4);
                Console.WriteLine("{0}", MathExtension.RoundDownFix(3.7d) == 3d);
                Console.WriteLine("{0}", MathExtension.RoundDownFix(-3.7d) == -4d);
                Console.WriteLine("{0}", MathExtension.RoundDownFix(3.1d) == 3d);
                Console.WriteLine("{0}", MathExtension.RoundDownFix(-3.1d) == -4d);
                Console.WriteLine("{0}", MathExtension.RoundUpFix(3.1d) == 4d);
                Console.WriteLine("{0}", MathExtension.RoundUpFix(-3.7d) == -3d);
                Console.WriteLine("{0}", MathExtension.RoundFix(3.5d) == 4d);
                Console.WriteLine("{0}", MathExtension.RoundFix(-3.5d) == -3d);
                Console.WriteLine("{0}", MathExtension.RoundTo(123.456d, 0) == 123.00d);
                Console.WriteLine("{0}", MathExtension.RoundTo(123.456d, 2) == 123.46d);
                Console.WriteLine("{0}", MathExtension.RoundTo(123456d, -3) == 123000d);
    #endif // CS3
            }
        }
    }

    위의 코드에서 CS3 라는 매크로를 프로젝트 내에 설정하면 Extension Method로 사용할 수 있으며, 이 매크로의 선언을 해제하면 일반 정적 메서드로 변경하여 사용할 수 있습니다. 여러 메서드들이 있지만 그 중에서도 RoundTo 메서드는 사용 빈도가 매우 많은 함수일 듯 합니다. :-)


    남정현 (rkttu@rkttu.com) - Visual Studio 2010 한국 공식 팀 블로그 멤버 - http://www.vsts2010.net | Windows Azure Cafe SYSOP - http://cafe.naver.com/wazure | DEVPIA C# Forum SYSOP - http://www.devpia.com/CSharp.MAEUL
    2010년 11월 25일 목요일 오전 3:01