文章目录

  • 前言
  • 一、问题
  • 二、分析
  • 三、实现
  • 1、界面设计
  • 2、循环小数类设计
  • 3、调用
  • 4、运行结果
  • 5、神奇的发现
  • 总结
  • 附录



前言

        最近学习C#,遇到这样的一个问题:用分数表示循环小数 0.33(3)=1/3   0.285714(285714)=2/7 ,解决之后来记录一下解决方案。

一、问题

        用分数表示循环小数 0.33(3)=1/3   0.285714(285714)=2/7

二、分析

        循环小数分纯循环小数和混循环小数。
        纯循环小数的化法:先获取循环体的值x,然后获取循环体的位数n,然后将循环体的值x比上n个9,最后化简。如,0.81(81),从这个数中我们可以获取循环体的值为81,循环体的位数为2也就是到时候比上99,所以得出0.81(81)=(81/99)=9/11。
        混循环小数的化法:先将其分解成为有限小数与纯循环小数/10^k的和(这里的k是指循环体前面的小数位数),然后分别求出它们的分数形式,最后通分化简。举例如下:0.13(3),这里分解出来的有限小数为0.1、纯循环小数为0.3(3)、k为1(因为循环体3前面的小数只有1位),所以得出0.13(3)=0.1+0.3(3)/10=2/15。
        注意点:如果像前面0.33(3)这样的数,它本来是纯循环小数,但是由于它不是写成0.3(3)这样的形式,如果把它归为纯循环小数来书写代码将会提高代码的复杂程度,所以我们把它归类于混循环小数来处理。

三、实现

1、界面设计

循环 List remove 循环小数怎么表示_System


        1、输入框:使用TextBox控件,并给它命名为cirNumTBox

        2、显示框:使用TextBox控件,给它命名为fracTBox,并将ReadOnly属性设置成true

        3、转换按钮:使用Button控件,并给它命名为changeBtn

2、循环小数类设计

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CycNumExpress
{
    /// <summary>
    /// 此类用来描述无限循环小数,拥有循环小数和分数两个属性
    /// </summary>
    public class CircleNum
    {
        string circNum; //循环小数
        public string CircNum
        {
            get { return circNum; }
            set { circNum = value; }
        }
        string fraction; //循环小数的分数表示

        public string Fraction
        {
            get { return fraction; }
            set { circNum = value; }
        }

        public CircleNum()
        {
        }

        public CircleNum(string circNum)
        {
            this.circNum = circNum;
            fraction = ChangeToFraction();
        }

        /// <summary>
        /// 此方法用来将无限循环小数转换成分数表示
        /// </summary>
        /// <returns>无限循环小数的分数表示</returns>
        public string ChangeToFraction()
        {
            string circBody; //循环体
            string acycBody; //非循环体
            int num;         //记录循环体前面小数点的位数
            string fraction;//分数

            circBody = GetCircBody(circNum);//获取循环体
            acycBody = GetAcycBody(circNum);//获取非循环体
            //获取循环体前的小数位数,如 1.13(3)其num的值为1
            num = GetBCirBodyDecimal(circNum);
            fraction = GetFraction(circBody, acycBody, num);//获取分数表示
            return fraction;
        }

        /// <summary>
        /// 此函数用来获取循环体,如1.13(3),则获取值为3
        /// </summary>
        /// <param name="circNum">循环小数</param>
        /// <returns>循环体</returns>
        public string GetCircBody(String circNum)
        {
            string circBody = "0";
            int firstIndex = circNum.IndexOf("(") + 1; //读的首位置下标
            int lastIndex = circNum.LastIndexOf(")") - 1;//读取的尾下标
            int readNum = lastIndex - firstIndex + 1;//读取的数目
            if ((firstIndex > 0) && readNum > 0)
            {
                circBody = circNum.Substring(firstIndex, readNum);//截取循环体
            }
            return circBody;
        }
        /// <summary>
        /// 此函数用来获取非循环体,如1.13(3),则获取值为1.1
        /// </summary>
        /// <param name="circNum">循环小数</param>
        /// <returns>非循环体</returns>
        public string GetAcycBody(String circNum)
        {
            string acycBody = "";
            int firstIndex = 0; //读的首位置下标
            int lastIndex = circNum.LastIndexOf(GetCircBody(circNum) + "(") - 1;//读取的尾下标
            int readNum = lastIndex - firstIndex + 1;//读取的数目
            if (firstIndex != -1 && readNum > 0)
            {
                acycBody = circNum.Substring(firstIndex, readNum);//截取循环体
                if (acycBody.EndsWith("."))//如果小数点后没有数了,那么就截去小数点
                {
                    acycBody = circNum.Substring(firstIndex, acycBody.Length - 1);//截取循环体
                }
            }
            else
            {
                acycBody = circNum;
            }
            return acycBody;
        }

        /// <summary>
        /// 此函数用来获取循环体前的小数位数,如 1.13(3)其num的值为1
        /// </summary>
        /// <param name="circNum">循环小数</param>
        /// <returns>循环体前的小数位数</returns>
        public int GetBCirBodyDecimal(String circNum)
        {
            int num = 0;
            string acycBody = GetAcycBody(circNum);
            int firstIndex = acycBody.IndexOf(".") + 1; //读的首位置下标
            int lastIndex = acycBody.Length - 1;//读取的尾下标
            int readNum = lastIndex - firstIndex + 1;//读取的数目
            if ((firstIndex > 0) && (readNum > 0))
            {
                num = acycBody.Substring(firstIndex, readNum).Length;//截取循环体
            }
            return num;
        }

        /// <summary>
        /// 此函数用来获取循环小数的分数表示
        /// </summary>
        /// <param name="circBody">循环体</param>
        /// <param name="acycBody">非循环体</param>
        /// <param name="num">循环体前的小数位</param>
        /// <returns>循环小数的分数表示</returns>
        public string GetFraction(string circBody, string acycBody, int num)
        {
            string fraction;
            long mol;         //分子
            long deno = 0;    //分母
            string op = "";
            if (int.Parse(circBody) == 0)
            {
                deno = 1;
            }
            else
            {
                for (int i = 1; i <= circBody.Length; ++i)
                    deno = deno * 10 + 9;
            }
            deno = deno * (int)Math.Pow(10, num);//为分母赋值
            mol = long.Parse(circBody) + (long)(Math.Abs(decimal.Parse(acycBody) * deno));//为分子赋值
            if (acycBody.Substring(0, 1) == "-")//记录循环小数的符号
            {
                op = "-";
            }
            long gcd = FindGCD(mol, deno);//寻找最大公约数
            fraction = op + (mol / gcd).ToString() + ((deno / gcd == 1) ? "" : "/" + (deno / gcd).ToString());//得到最简分数
            return fraction;
        }

        /// <summary>
        /// 本函数用辗转相除法来求解最大公约数
        /// </summary>
        /// <param name="num1">整数1</param>
        /// <param name="num2">整数2</param>
        /// <returns>最大公约数</returns>
        public long FindGCD(long num1, long num2)
        {
            long temp;
            num1 = Math.Abs(num1);
            num2 = Math.Abs(num2);
            temp = num1 % num2;
            while (temp != 0)
            {
                num1 = num2;
                num2 = temp;
                temp = num1 % num2;
            }
            return num2;
        }
    }
}

3、调用

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CycNumExpress
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void change(object sender, EventArgs e)
        {
            //有参构造实现
            //CircleNum circNum = new CircleNum(cirNumTBox.Text);
            //fracTBox.Text = circNum.Fraction;

            //无参构造实现
            CircleNum circNum = new CircleNum();
            circNum.CircNum = cirNumTBox.Text;
            fracTBox.Text = circNum.ChangeToFraction();

        }
    }
}

4、运行结果

纯循环小数转换

循环 List remove 循环小数怎么表示_c#_02


循环 List remove 循环小数怎么表示_c#_03


混循环小数转换

循环 List remove 循环小数怎么表示_ci_04


整数转换

循环 List remove 循环小数怎么表示_c#_05


有限小数转换

循环 List remove 循环小数怎么表示_System_06

5、神奇的发现

        在不断测试的过程中,遇到了一个神奇的事情,在循环小数中,如果带有9的循环体,那么就会得到近似解,比如0.9(9)=1。刚刚发现被惊到了,还以为遇到什么神奇的bug,后来仔细一想这个结果是正确的,详细证明过程如下:

证明1:
        设0.9(9)=x。
        那么:10x=9.9(9)则9x=10x-x=9.9(9)-0.9(9)=9。
        所以x=1,得证。

证明2:
        设0.9 (9)为无限递缩等比数列。
        那么:0.9(9)=0.9+0.09+0.009+…+0.90.1的(n-1)次方=
                    0.9
(1-0.1的n次方)/(1-0.1)=1-0.1的n次方。
        所以当n趋向于无穷大时0.1的n次方趋向于0 所以0.9(9)=1。

循环 List remove 循环小数怎么表示_System_07

总结

        将循环小数转换成其分数形式看起来复杂,但是经过分析,将问题分解细化,还是可以找到比较好的解决方案的,希望此篇文章可以帮助到你。

附录

源码下载:https://github.com/luotingyang/MyRepository/tree/C%23