求解分数(真分数和假分数)的循环周期

今天偶然遇到一个问题,要求解一个无限循环小数的循环周期,如3/7 = 0.428571428571428571.....,那么循环周期则为6。这是真分数的求法,另外还应当考虑到除数比被除数小的情况下,即假分数的情况的处理。

采用浮点数移位+强制类型转换+求模的方式:


int cycle(int m,int n){
	int cycle=0;
	double rational_num,tmp;
	int int_rat,int_tmp;
	rational_num =(double) m/n;
	rational_num = rational_num-(int)rational_num;//将整数部分舍去,进行归一化处理
	tmp = rational_num;
	while(int_tmp != int_rat||(cycle == 0)){
		cycle++;
		tmp *=10;
		rational_num *=100;
		int_tmp = (int)tmp;
		int_rat = (int)rational_num%decade(cycle);//decade表示计算10的cycle次方
	}
	return cycle;
}

这种方式存在很多问题:首先,在强制类型转换的时候,会有溢出和截断出现,导致数变成了负数,无法求得最终结果。其次,在计算机中,单精度浮点和双精度浮点数都是有精度的,计算机的计算方式和人的计算方式也不一样,可能在小数点几位以后就已经失真了(单精度连一次循环都无法进行就出错了),最后结果也无法保证。最后,通过这种大规模的加减乘除运算,导致了计算的效率很低,而且上面这个程序依赖于“大数高精度除法”的精确实现,否则就没有 意义(上述程序到最后也没出正确结果)。

采用类型转换+字符串匹配的方式:


这种方式是用空间换时间的方式,将计算好的数转换成字符串类型,然后采用成熟的库中的字符串匹配方法进行最大重复子穿的匹配就可以了,代码可读性高,较为简洁,但是要注意对归一化以后的数字进行类型转换,避免做无用功。
这种方式有个显著的缺点,如果循环的周期很大,本身在归一化处理的时候就将原来的数字进行截断了,那么再进行后面的比较的时候就毫无意义。

采用模余运算+移位的方式:

这种方式是目前能想到的最好的方式:
不用进行归一化处理,每次计算分母被分子除后的余数并保存,当两次运算余数相同的时候,那么两次相同余数的计算次数间隔则为周期:

while(!exist((m%n),a)){//a[] 是存储余数的数组
		insert((m%n),a);
		m*=10;
		m=m%n;
		cycle ++;
	}

这种方式效率较高,但是在判断是否已经存在元素和插入新余数的时候要有个O(cycle)的时间复杂度的遍历,但相对于上述两种方式的计算和转换以及对空间的浪费,这种方式在准确度,效率和鲁棒性上都有提高。
目前还有待改进的一点是,如果一个循环周期内存在两次相同的余数(在除数大于10的情况下会出现),那么所求得的周期就会出现问题,需要加标志位进行判断。
其实在处理这种匹配和查找的时候,python语言很有优势,通过简单的list中的filter和spilt就基本能够完成。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值