精确表达浮点数

package com.demo;


import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 精确表达浮点数
 * 在计算机中,有时使用float或double来存储小数是不能能到精确值的。如果你希望得
 * 到精确计算的结果,最好是用分数形式来表示小数。有限小数或者无限循环小数都可以
 * 转化为分数。比如:
 * 0.9 = 9/10
 * 0.333(3) = 1/3(括号中的数字表示是循环节)
 * 当然一个小数可以用好几种分数形式来表示。如:
 * 0.333(3) = 1/3 = 3/9
 * 
 * 给定一个有限小数或无限循环小数,你能否以父母最小的分数形式来返回这个小数
 * 呢?如果输入为循环小数,循环节用括号标记出来。下面是一些可能的输入数据,如
 * 0.3、0.30、0.3(000)、0.3333(3333)、......
 * @author ying
 *
 */


public class AccurateExpressFloat {
/**
* 拿到这样一个问题,我们往往会从最简单的情况入手,因为所有的小数都可以分解成
* 一个整数和一个纯小数之和,不防只考虑大于0、小于1的纯小数,且暂时不考虑分子
* 和分母的约分。题目中输入的小数,要么为有限小数X=0.a1a2...an,要么为无限循环
* 小数X=0.a1a2...an(b1b2...bm),X表示式中的字母a1a2...an,b1b2...bm都是0-9的
* 数字,括号部分(b1b2...bm)表示循环节,我们需要处理的就是以上两种情况。

* 对于无限循环小数X=0.a1a2...an(b1b2...bm)来说,其复制部分在于小数点后同时有
* 非循环部分和循环部分,我们可以做如下的转换:
* X=0.a1a2...an(b1b2...bm)
* =>10(n)*X=a1a2...an(b1b2...bm)(10(n)表示10的n次方)
* =>10(n)*X=a1a2...an+0.(b1b2...bm)
* =>X=(a1a2...an+0.(b1b2...bm))/10(n)

* 对于整数部分a1a2...an,不需要做额外处理,只需要把小数部分转换为分数形式再加上
* 这个整数即可。对于后面的无限循环部分,可以采用如下方式进行处理:
* 令Y=0.(b1b2...bm),那么
* 10(m)*Y=b1b2...bm.(b1b2...bm)
* =>10(m)*Y=b1b2...bm+0.(b1b2...bm)
* =>10(m)*Y-Y=b1b2...bm
* =>Y=b1b2...bm/(10(m)-1)
* 将Y代入前面的X的等式可得:
* X=(a1a2...an+Y)/10(n)
*  =(a1a2...an+b1b2...bm/(10(m)-1))/10(n)
*  =((a1a2...an)*(10(m)-1)+(b1b2...bm)/((10(m)-1)*10(n)))
*  至此,便可以得到任意一个有效小数或无限循环小数的分数表示,但是此时分母未
*  必是最简的,应该对分子和分母进行约分。
*  
*  例如,对于小数0.3(33),根据上诉方法,可以转化为分数:
*  0.3(33)
*  =(3*(10(2)-1)+33)/((10(2)-1)*10)
*  =(3*99+33)/990
*  =1/3
*  
*  对于小数0.285714(285714),我们也可以算出:
*  0.285714(285714)
*  =(285714*(10(6)-1)+285714)/((10(6)-1)*10(6))
*  =(285714*999999+285714)/999999000000
*  285714/999999
*  2/7
* @param x
* @return
*/
public String method1(String x){
long integerNum = getInteger(x,1);//整数部分
long decimalNum = getInteger(x,2);//小数部分
long circleNum = getInteger(x,3);//循环部分
long n = getBit(decimalNum);//获得小数部分的位数
long m = getBit(circleNum);//获得循环部分的位数
long numerator  = (long) (decimalNum * (Math.pow(10, m)-1)+circleNum);//分子
long denominator =(long) ((Math.pow(10, m)-1)*Math.pow(10, n)) ;//分母
long gcdNum = gcd(numerator,denominator);//求两个数的最大公约数
denominator /=gcdNum;//分子约分
numerator = (numerator/gcdNum)+denominator*integerNum;//分母约分加上整数部分
return "转化为分数形式为:"+numerator+"/"+denominator;
}
public long gcd(long x,long y){
if(x < y)
return gcd(y,x);
if(y == 0)
return x;
else{
if(isEven(x)){
if(isEven(y))
return (gcd(x>>1,y>>1)<<1);
else
return gcd(x>>1,y);
}else{
if(isEven(y))
return gcd(x,y>>1);
else
return gcd(y,x-y);
}
}
}
/**
* 判断是否为偶数,如果x为偶数,则返回true,否则放回false。
* @param x
* @return
*/
public boolean isEven(long x){
if(x % 2 == 0)
return true;
else
return false;
}
/**
* 获得一个数字的位数
* @param num
* @return
*/
public long getBit(long num){
long k = 1;
while(num / 10 != 0){
num /= 10;
k++;
}
return k;
}
/**

* @param x循环小数字符串
* @param flag 1表示获取整数部分,2表示获取小数部分,3表示获取循环部分
* @return
*/
public long getInteger(String x,int flag){
String regEx = "([0-9]+)[.]?([0-9]*)[(]?([0-9]*)[)]?";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(x);
String temp = "";
if(matcher.find()){
if(matcher.groupCount() < flag){
return 0;
}else{
temp = matcher.group(flag);
if(temp.length() == 0)
temp = "0";
return Long.parseLong(temp);
}
}
return 0;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值