С# Вывести дробное число прописью

Я позаимствовал этот код для вывода суммы и он работает отлично. Появилась необходимость в реализации вывода дробных чисел прописью, в частности процентов. Например, 0,01% - ноль целых одна сотая процента или 1,032% - одна целая тридцать две тысячных процентов. Вроде бы, можно этот код адаптировать под мои нужды. Есть идеи?

    public class RUBWord
    {
        private static string[] hunds =
        {
            "", "сто ", "двести ", "триста ", "четыреста ",
            "пятьсот ", "шестьсот ", "семьсот ", "восемьсот ", "девятьсот "
        };

        private static string[] tens =
        {
            "", "десять ", "двадцать ", "тридцать ", "сорок ", "пятьдесят ",
            "шестьдесят ", "семьдесят ", "восемьдесят ", "девяносто "
        };

        public static string Str(int val, bool male, string one, string two, string five)
        {
            string[] frac20 =
            {
                "", "один ", "два ", "три ", "четыре ", "пять ", "шесть ",
                "семь ", "восемь ", "девять ", "десять ", "одиннадцать ",
                "двенадцать ", "тринадцать ", "четырнадцать ", "пятнадцать ",
                "шестнадцать ", "семнадцать ", "восемнадцать ", "девятнадцать "
            };

            int num = val % 1000;
            if(0 == num) return "";
            if(num < 0) throw new ArgumentOutOfRangeException("val", "Параметр не может быть отрицательным");
            if(!male)
            {
                frac20[1] = "одна ";
                frac20[2] = "две ";
            }

            StringBuilder r = new StringBuilder(hunds[num / 100]);

            if(num % 100 < 20)
            {
                r.Append(frac20[num % 100]);
            }
            else
            {
                r.Append(tens[num % 100 / 10]);
                r.Append(frac20[num % 10]);
            }
            
            r.Append(Case(num, one, two, five));

            if(r.Length != 0) r.Append(" ");
            return r.ToString();
        }

        public static string Case(int val, string one, string two, string five)
        {
            int t=(val % 100 > 20) ? val % 10 : val % 20;

            switch (t)
            {
                case 1: return one;
                case 2: case 3: case 4: return two;
                default: return five;
            }
        }
    };

    struct CurrencyInfo
    {
        public bool male;
        public string seniorOne, seniorTwo, seniorFive;
        public string juniorOne, juniorTwo, juniorFive;
    };

    public class RusCurrencySectionHandler:IConfigurationSectionHandler
    {
        public object Create( object parent, object configContext, XmlNode section )
        {
            foreach(XmlNode curr in section.ChildNodes)
            {
                if(curr.Name=="currency")
                {
                    XmlNode senior=curr["senior"];
                    XmlNode junior=curr["junior"];
                    RusCurrency.Register(   
                        curr.Attributes["code"].InnerText,
                        (curr.Attributes["male"].InnerText == "1"),
                        senior.Attributes["one"].InnerText,
                        senior.Attributes["two"].InnerText,
                        senior.Attributes["five"].InnerText,
                        junior.Attributes["one"].InnerText,
                        junior.Attributes["two"].InnerText,
                        junior.Attributes["five"].InnerText);
                }
            }
            return null;
        }
    };
            
    public class RusCurrency
    {
        private static HybridDictionary currencies = new HybridDictionary();

        static RusCurrency()
        {
            Register("RUB", true, "рубль", "рубля", "рублей", "копейка", "копейки", "копеек");          
            Register("EUR", true, "евро", "евро", "евро", "евроцент", "евроцента", "евроцентов");           
            Register("USD", true, "доллар", "доллара", "долларов", "цент", "цента", "центов");          
            ConfigurationSettings.GetConfig("currency-names");
        }

        public static void Register(string currency, bool male, 
            string seniorOne, string seniorTwo, string seniorFive,
            string juniorOne, string juniorTwo, string juniorFive)
        {
            CurrencyInfo info;
            info.male = male;
            info.seniorOne = seniorOne; info.seniorTwo = seniorTwo; info.seniorFive = seniorFive; 
            info.juniorOne = juniorOne; info.juniorTwo = juniorTwo; info.juniorFive = juniorFive;
            currencies.Add(currency, info);
        }

        public static string Str(double val)
        {
            return Str(val, "RUB");
        }

        public static string Str(double val, string currency)
        {
            if(!currencies.Contains(currency)) 
                throw new ArgumentOutOfRangeException("currency", "Валюта \""+currency+"\" не зарегистрирована");
            
            CurrencyInfo info = (CurrencyInfo)currencies[currency];
            return Str(val, info.male, 
                info.seniorOne, info.seniorTwo, info.seniorFive,
                info.juniorOne, info.juniorTwo, info.juniorFive);
        }

        public static string Str(double val, bool male, 
            string seniorOne, string seniorTwo, string seniorFive,
            string juniorOne, string juniorTwo, string juniorFive)
        {
            bool minus = false;
            if(val < 0) { val = - val; minus = true; }

            int n = (int) val;
            int remainder = (int) (( val - n + 0.005 ) * 100);

            StringBuilder r = new StringBuilder();

            if(0 == n) r.Append("0 ");
            if(n % 1000 != 0)
                r.Append(RUBWord.Str(n, male, seniorOne, seniorTwo, seniorFive));
            else
                r.Append(seniorFive);

            n /= 1000;
         
            r.Insert(0, RUBWord.Str(n, false, "тысяча", "тысячи", "тысяч"));
            n /= 1000;
         
            r.Insert(0, RUBWord.Str(n, true, "миллион", "миллиона", "миллионов"));
            n /= 1000;
         
            r.Insert(0, RUBWord.Str(n, true, "миллиард", "миллиарда", "миллиардов"));
            n /= 1000;
         
            r.Insert(0, RUBWord.Str(n, true, "триллион", "триллиона", "триллионов"));
            n /= 1000;
         
            r.Insert(0, RUBWord.Str(n, true, "триллиард", "триллиарда", "триллиардов"));
            if(minus) r.Insert(0, "минус ");

            r.Append(remainder.ToString("00 "));
            r.Append(RUBWord.Case(remainder, juniorOne, juniorTwo, juniorFive));
         
            return r.ToString();
        }
    };

Реализация кода:

RusCurrency.Str(number)

Ответы (1 шт):

Автор решения: ShewRN

Сам додумался до решения. Выкладываю код, если кому-то понадобится.

Работает до стотысячных, но Вы можете добавить больше разрядов, дописав ещё case.

using System;
using System.Text;
using System.Xml;
using System.Configuration;
using System.Collections.Specialized;

namespace Intant_App_Core_
{
    public class PercentWord
    {
        private static string[] hunds =
        {
            "", "сто ", "двести ", "триста ", "четыреста ",
            "пятьсот ", "шестьсот ", "семьсот ", "восемьсот ", "девятьсот "
        };

        private static string[] tens =
        {
            "", "десять ", "двадцать ", "тридцать ", "сорок ", "пятьдесят ",
            "шестьдесят ", "семьдесят ", "восемьдесят ", "девяносто "
        };

        public static string Str(int val, bool male, string one, string two, string five)
        {
            string[] frac20 =
            {
                "", "один ", "два ", "три ", "четыре ", "пять ", "шесть ",
                "семь ", "восемь ", "девять ", "десять ", "одиннадцать ",
                "двенадцать ", "тринадцать ", "четырнадцать ", "пятнадцать ",
                "шестнадцать ", "семнадцать ", "восемнадцать ", "девятнадцать "
            };

            int num = val % 1000;
            if (0 == num) return "";
            if (num < 0) throw new ArgumentOutOfRangeException("val", "Параметр не может быть отрицательным");
            if (!male)
            {
                frac20[1] = "одна ";
                frac20[2] = "две ";
            }

            StringBuilder r = new StringBuilder(hunds[num / 100]);

            if (num % 100 < 20)
            {
                r.Append(frac20[num % 100]);
            }
            else
            {
                r.Append(tens[num % 100 / 10]);
                r.Append(frac20[num % 10]);
            }

            r.Append(Case(num, one, two, five));

            if (r.Length != 0) r.Append(" ");
            return r.ToString();
        }

        public static string Case(int val, string one, string two, string five)
        {
            int t = (val % 100 > 20) ? val % 10 : val % 20;

            switch (t)
            {
                case 1: return one;
                case 2: case 3: case 4: return two;
                default: return five;
            }
        }
    };

    struct CurrencyInform
    {
        public bool male;
        public string seniorOne, seniorTwo, seniorFive;
        public string juniorOne, juniorTwo, juniorFive;
    };

    public class PercentCurrency
    {
        private static HybridDictionary currencies = new HybridDictionary();

        static PercentCurrency()
        {
            Register("Perc", true, "целая", "целых", "целых", "", "", "");
            ConfigurationSettings.GetConfig("currency-names");
        }

        public static void Register(string currency, bool male,
            string seniorOne, string seniorTwo, string seniorFive,
            string juniorOne, string juniorTwo, string juniorFive)
        {
            CurrencyInfo info;
            info.male = male;
            info.seniorOne = seniorOne; info.seniorTwo = seniorTwo; info.seniorFive = seniorFive;
            info.juniorOne = juniorOne; info.juniorTwo = juniorTwo; info.juniorFive = juniorFive;
            currencies.Add(currency, info);
        }

        public static string Str(double val)
        {
            if (val.ToString().Contains(',') == false)
            {
                string result = PercentWord.Str((int)val, true, ") процента", ") процента", ") процентов");
                int match = result.IndexOf(" )");
                return result.Remove(match, 1);
            }
            else
                return Str(val, "Perc");
        }

        public static string Str(double val, string currency)
        {
            if (!currencies.Contains(currency))
                throw new ArgumentOutOfRangeException("currency", "Валюта \"" + currency + "\" не зарегистрирована");

            CurrencyInfo info = (CurrencyInfo)currencies[currency];
            return Str(val, info.male, info.seniorOne, info.seniorTwo, info.seniorFive);
        }

        public static string Str(double val, bool male,
            string seniorOne, string seniorTwo, string seniorFive)
        {
            bool minus = false;
            if (val < 0) { val = -val; minus = true; }

            int n = (int)val;
            string remainder = val.ToString().Split(',')[1];

            StringBuilder r = new StringBuilder();

            if (0 == n) r.Append("ноль ");
            if (n % 1000 != 0)
                r.Append(PercentWord.Str(n, male, seniorOne, seniorTwo, seniorFive));
            else
                r.Append(seniorFive + " ");

            n /= 1000;

            r.Insert(0, PercentWord.Str(n, false, "тысяча", "тысячи", "тысяч"));
            n /= 1000;

            r.Insert(0, PercentWord.Str(n, true, "миллион", "миллиона", "миллионов"));
            n /= 1000;

            r.Insert(0, PercentWord.Str(n, true, "миллиард", "миллиарда", "миллиардов"));
            n /= 1000;

            r.Insert(0, PercentWord.Str(n, true, "триллион", "триллиона", "триллионов"));
            n /= 1000;

            r.Insert(0, PercentWord.Str(n, true, "триллиард", "триллиарда", "триллиардов"));
            if (minus) r.Insert(0, "минус ");

            switch (remainder.Length)
            {
                case 1:
                    r.Append(PercentWord.Str(Convert.ToInt32(remainder), false, "десятая процента", "десятых процентов", "десятых процентов"));
                    break;
                case 2:
                    r.Append(PercentWord.Str(Convert.ToInt32(remainder), false, "сотая процента", "сотых процентов", "сотых процентов"));
                    break;
                case 3:
                    r.Append(PercentWord.Str(Convert.ToInt32(remainder), false, "тысячная процента", "тысячных процентов", "тысячных процентов"));
                    break;
                case 4:
                    r.Append(PercentWord.Str(Convert.ToInt32(remainder), false, "десятитысячная процента", "десятитысячных процентов", "десятитысячных процентов"));
                    break;
                case 5:
                    r.Append(PercentWord.Str(Convert.ToInt32(remainder), false, "стотысячная процента", "стотысячных процентов", "стотысячных процентов"));
                    break;
            }
            return r.ToString();
        }
    };
}

Реализация кода:

PercentCurrency.Str(doubleNumb)
→ Ссылка