Comment detail
分数を小数に展開 (Nested Flatten)This comment is reply for 567 こう。: かなり奥深いですね。 数学的に解いてみ...(分数を小数に展開). Go to thread root.
多分、この辺がベストかな?表示以外にはほとんど時間はかからないはず。関数名は考えるのまんどくなったw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | #include <stdio.h>
#include <stdlib.h>
//小数の表示
void put_decimal(int a,int b,int loop_start_pos){
int i;
long long mod;
long long loop_start_mod;
printf("%d/%d=%d.",a,b,a/b);
mod=(long long)(a%b)*10;
//循環節までを表示
for(i=0;i<loop_start_pos;i++){
putchar('0'+(int)(mod/b));
mod=(mod%b)*10;
if(mod==0){
putchar('\n');
return;
}
}
loop_start_mod=mod;
//循環節を表示
putchar('{');
do{
putchar('0'+(int)(mod/b));
mod=(mod%b)*10;
i++;
}while(mod!=loop_start_mod);
puts("}");
}
void put_decimals4(int a,int b){
long long i,j;
long long mod_buf[31]; //循環開始位置チェック用のバッファ
long long mod; //余り
int num_2,num_5; //素因数分解の結果:2の乗数、5の乗数
long long nonloop_max; //非循環部の最大桁数
long long loop_max; //循環部の最大桁数
int denom; //計算用分母
if(a%b==0){
printf("%d/%d=%d\n",a,b,a/b);
return;
}
denom=b;
//bの2,5についての素因数分解
num_2=0;
num_5=0;
while(denom%2==0){
denom/=2;
num_2++;
}
while(denom%5==0){
denom/=5;
num_5++;
}
nonloop_max=max(num_2,num_5);
loop_max=denom;
//素因数に2,5を含まなければ純循環関数
if(nonloop_max==0){
//純循環小数なので表示
put_decimal(a,b,0);
return;
}
//もし分子がdenomの倍数なら約分できる。
//分母が2^x*5^yであるなら非循環小数
if(loop_max==1&&a%denom==0){
//非循環関数なので表示
put_decimal(a,b,nonloop_max);
return;
}
//循環節ありの循環小数
mod=a%b*10;
mod_buf[0]=mod;
//循環節の開始位置を探す。
for(i=1;i<loop_max+nonloop_max;i++){
mod=(mod%b)*10;
//非循環候補の取り込み
if(i<=nonloop_max){
mod_buf[i]=mod;
}
//バッファ内との循環チェック
for(j=0;j<=min(i,nonloop_max);j++){
if(mod==mod_buf[j]){
//循環開始位置がわかったら表示
put_decimal(a,b,j);
return;
}
}
}
//必ず非循環か循環のはずなのでここに来ることはない。
return;
}
int main(){
put_decimals4( 3, 30);
put_decimals4( 3, 8);
put_decimals4( 3, 14);
put_decimals4( 1, 3);
put_decimals4( 9, 3);
put_decimals4( 1, 11);
put_decimals4( 31, 701);
put_decimals4( 101, 1999);
put_decimals4( 1,2097152000); //最小の非循環小数?
put_decimals4(1073741823,1073741824); //最長の非循環小数?
put_decimals4( 21474836,2147483629); //最長の循環小数?
return 0;
}
|
やっぱちょっと修正。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | //小数の表示
void put_decimal(int a,int b,int non_loop_size){
int i;
long long mod;
long long loop_start_mod;
printf("%d/%d=%d.",a,b,a/b);
mod=(long long)(a%b)*10;
//循環節までを表示
for(i=0;i<non_loop_size;i++){
putchar('0'+(int)(mod/b));
mod=(mod%b)*10;
if(mod==0){
putchar('\n');
return;
}
}
loop_start_mod=mod;
//循環節を表示
putchar('{');
do{
putchar('0'+(int)(mod/b));
mod=(mod%b)*10;
i++;
}while(mod!=loop_start_mod);
puts("}");
}
void put_decimals4(int a,int b){
long long i,j;
long long mod_buf[31];
long long mod;
int num_2,num_5; //素因数分解の結果:2の乗数、5の乗数
long long nonloop_max; //非循環部の最大桁数
long long loop_max; //循環部の最大桁数
int num,denom; //判別計算用分子、分母
if(a%b==0){
printf("%d/%d=%d\n",a,b,a/b);
return;
}
num=a;
denom=b;
//2,5で約分
while(num%2==0&&denom%2==0){
num/=2;
denom/=2;
}
while(num%5==0&&denom%5==0){
num/=5;
denom/=5;
}
//分母の2,5についての素因数分解
num_2=0;
num_5=0;
while(denom%2==0){
denom/=2;
num_2++;
}
while(denom%5==0){
denom/=5;
num_5++;
}
nonloop_max=max(num_2,num_5);
loop_max=denom;
//素因数に2,5を含まなければ純循環関数
if(nonloop_max==0){
//純循環小数なので表示
put_decimal(a,b,0);
return;
}
//もし分子がdenomの倍数なら約分できる。
//分母が2^x*5^yであるなら非循環小数
if(loop_max==1&&a%denom==0){
//非循環関数なので表示
put_decimal(a,b,nonloop_max);
return;
}
//循環節ありの循環小数
mod=a%b*10;
mod_buf[0]=mod;
//循環節の開始位置を探す。
for(i=1;i<loop_max+nonloop_max;i++){
mod=(mod%b)*10;
//非循環候補の取り込み
if(i<=nonloop_max){
mod_buf[i]=mod;
}
//バッファ内との循環チェック
for(j=0;j<=min(i,nonloop_max);j++){
if(mod==mod_buf[j]){
//循環開始位置がわかったら表示
put_decimal(a,b,j);
return;
}
}
}
//必ず非循環か循環のはずなのでここに来ることはない。
return;
}
|
さらにミス発見orz
1 2 3 4 | Ã
for(j=0;j<=min(i,nonloop_max);j++){
○
for(j=0;j<=min(i-1,nonloop_max);j++){
|
結局のところ、これでよさげ。
もう少し計算したらloop_maxじゃなく、実際の循環部の長さも求められそうなんだけど、どうなんだろ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | void put_decimals5(int a,int b){
long long i;
long long mod;
int num_2,num_5; //素因数分解の結果:2の乗数、5の乗数
long long nonloop_max; //非循環部の最大桁数
// long long loop_max; //循環部の最大桁数
long long loop_start_mod; //循環節開始時の余り
int num,denom; //計算用分母
printf("%d/%d=%d",a,b,a/b);
if(a%b==0){
putchar('\n');
return;
}
a%=b;
num=a;
denom=b;
//2,5で約分
while(num%2==0&&denom%2==0){
num/=2;
denom/=2;
}
while(num%5==0&&denom%5==0){
num/=5;
denom/=5;
}
//分母の2,5についての素因数分解
num_2=0;
num_5=0;
while(denom%2==0){
denom/=2;
num_2++;
}
while(denom%5==0){
denom/=5;
num_5++;
}
nonloop_max=max(num_2,num_5);
// loop_max=denom;
putchar('.');
mod=(long long)(a%b)*10;
//非循環部を表示
for(i=0;i<nonloop_max;i++){
putchar('0'+(int)(mod/b));
mod=(mod%b)*10;
}
if(mod){
//循環節を表示
loop_start_mod=mod;
putchar('{');
do{
putchar('0'+(int)(mod/b));
mod=(mod%b)*10;
}while(mod!=loop_start_mod);
putchar('}');
}
putchar('\n');
return;
}
|
#312です。 Cだと商と剰余をいっぺんに取る関数ありませんでしたっけ? ループ中に割り算が半分になるので速くなると思います。 あと速度にはあまり影響なさそうですけど約分は既約分数を求めるとかでしょうか。
ものすごく興ざめな話ですが、循環小数の指数については『数論入門 / 北村泰一著』あたりをどうぞ。
それはそれでありですけど、「どう書く?」っていうのがここの趣旨だと思います。
読んで(知った上で)または、読まずに(知らないなりに)、どう書くかが問われるのでは?
だからものすごく興ざめな話なわけです。(^^;A






こう。 #568() [ Other ] Rating0/0=0.00
Rating0/0=0.00-0+