小数化为分数
可以化为分数形式的小数有两类:一类是有限小数,一类是无限循环小数。
对于有限小数,我们只要将小数点移到最右,然后除以相应的10的几次方, 最后再约分即可。例如0.1234 就是1234/10000。
而对于无限循环小数,我们先从一个最简单的例子来分析 – 0.(1) , 即0.11111…, 这里使用括号表示最小的循环节, 那么它对应的分数是多少呢?我们很容易得知如果将0.(1)乘以9的话,结果就是0.(9), 又因为它是无限循环的,所以0.(9)会无限地接近于1,那么我们可以说,0.(1) = 1/9, 这个式子从右往左推是显然的,从左往右推则需要将0.(9)近似地看作1才行。
那么对于更加复杂一点的呢。比如 0.(345), 我们可以使用同样的方法,考虑到
0.(345)=345∗0.(001)
而
0.(001)∗999=0.(999)=0.(9)=1
所以
0.(345)=345∗1999=345999
综合上面两点,我们可以求出任何形式的小数的分数形式,再举个例子,0.23(45),我们只要将它变成
0.23(45)=0.23+0.001∗0.(45)
即可分别求解。代码如下:
/*==================================================*\
| 小数化为分数 -- p/q(分子/分母)
| 括号表示循环节 -- 0.23(45) = 0.23454545...
\*==================================================*/
void DecToFrac(char str[], int& p, int& q) {
int a = 0, b = 0;
int L1 = 0,L2 = 0;
int len = strlen(str);
for(int i = 2; i < len; i++) {
if(str[i] == '(') break;
a = a * 10 + str[i] - '0';
L1++;
}
bool flag = 0;
for(int i = 2; i < len; i++) {
if(str[i] == '(' || str[i] == ')') {
flag = 1; continue;
}
b = b * 10 + str[i] - '0';
L2++;
}
L2 -= L1;
p = b - a; q = 0;
if(!flag) {
p = b; q = 1; L2 = 0;
}
for(int i = 0; i < L2; i++)
q = q * 10 + 9;
for(int i = 0; i < L1; i++)
q = q * 10;
int g = gcd(p, q);
p /= g; q /= g;
}
分数化为小数
直接模拟除法即可,注意求循环节可用一个vis数组记录余数是否出现过,要求循环节还可用一个pre数组记录此余数上次出现的位置。
/*==================================================*\
| 分数化为小数 -- 求1/n的分数
| 输出第一个循环节(如果有)
\*==================================================*/
void FracToDec(int n) {
bool isNeg = 0; if(n < 0) { n = -n; isNeg = 1; } //负数标志
int res[maxn], ok[maxn];
met(res, 0); met(ok, 0);
int k = 1; ok[k] = 1;
int cnt = 0;
W(k && n != 1) {
k *= 10; res[cnt++] = k / n; k %= n;
if(ok[k]) break; ok[k] = 1;
}//模拟除法
//输出
if(isNeg) printf("-"); if(n == 1) puts("1");
else {
printf("0.");
rep(i, 0, cnt) printf("%d", res[i]);
puts("");
}
}
循环节
这个要等到看完素数测试和高精度分解因式之后了。。。
小数问题