循環小数の計算について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
カステラ

循環小数の計算について

#1

投稿記事 by カステラ » 7ヶ月前

C言語で循環小数の循環節を表示するプログラムをおしえてください

例えば1/7の時は0.(142857)と表示させるプログラムを教えてください
自分でも書いてみたのですが、1/7の計算のとき
0.(142857142857)と循環節が2回
表示されてしまいます
#include <stdio.h>
int main(void)
{
int i;
int a[20],b,c,f,n,d,q,r;
f=0,b=0;
for(i = 0; i < 10; i++){
a = 0;
}
d=1;
printf("分母を入力: ");
scanf("%d", &n);

q = d / n;
r = d % n;
printf("%d / %d = %d.", d, n, q);
while(r!=0){
d = r *10;
q = d / n;
r = d % n;
if(f==0){
printf("(");
f++;
}
if (a[q] == 2){
printf(")");
break;
}
a[q]++;
printf("%d", q);
}
printf("\n");
return 0;
}

box
記事: 1695
登録日時: 7年前

Re: 循環小数の計算について

#2

投稿記事 by box » 7ヶ月前

1/7だったら循環節に現われる数字がすべて異なるので対処のしようがあると思いますが、
例えば1/17だったら循環節に同じ数字が複数回現われます。そこをどう切り抜けるかがポイントとなりそうです。
1/17 = 0.05882352941176470588235294117647...
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

かずま

Re: 循環小数の計算について

#3

投稿記事 by かずま » 7ヶ月前

カステラ さんが書きました: 自分でも書いてみたのですが、1/7の計算のとき
0.(142857142857)と循環節が2回
表示されてしまいます
if (a[q] == 2) { の意味を考えていますか?
「同じ商が既に 2回出ていれば、")" を表示して
ループを抜ける」なので、そうなるのは当然です。
カステラ さんが書きました:C言語で循環小数の循環節を表示するプログラムをおしえてください
例えば1/7の時は0.(142857)と表示させるプログラムを教えてください
このページの下の「検索」に「循環小数」と入力し、
右の検索ボタンを押してみてください。

修正できたら、codeタグを使って、そのプログラムを
貼り付けてください。

shika

Re: 循環小数の計算について

#4

投稿記事 by shika » 7ヶ月前

数学的視点での考察です。

1/p=(10^(p-1)-1)/p/(10^(p-1)-1)
で、pは素数の場合です。10^q-1 mod p = 0
と成る、最小整数qが見つかれば、それで循環します。
不完全な方法ですが、一応部分的に可能です。
一般整数の場合は、誤差が生じて、難しいのも事実です。
計算機のみの場合、1/5ですら、複雑な誤差処理を必要とします。
実体験にもとずいた教訓です。
少しでも参考になれば幸いです。
自分が理想とするプログラムを諦めないで下さい。
決して無駄には成りません。

zeek

Re: 循環小数の計算について

#5

投稿記事 by zeek » 7ヶ月前

「循環小数の循環節」は
①循環節の開始位置を求める
②循環節の終了位置を求める
ことで決定できます。
①循環節の開始位置を求める
 小数点から循環小数開始前までの桁数を非循環小数桁数として、この桁数を求めます。
 具体的には、約分を実施後の分母に対して 10 で割り切れる回数と 5 で割り切れる回数と
 2 で割り切れる回数を足した値で求められます。

コード:

 
num を約分後の分母として、小数点以下の非循環小数桁数は以下の関数で取得可能
int GetNonCyclicDigits(unsigned num)
{
    static const int dat[] = { 10, 5, 2 };
    int dig = 0;
    if (num != 0) {
        for (int i = 0; i < sizeof dat / sizeof dat[0]; ++i) {
            while (num % dat[i] == 0) {
                num /= dat[i], ++dig;
            }
        }
    }
    return dig;
}

②循環節の終了位置を求める
 非循環小数桁数 + 1 桁目が循環小数開始桁になりますのでこの位置における余りを保存し、
 以降の計算で同じ余りになった時点で循環小数が終了していることがわかります。

返信

“C言語何でも質問掲示板” へ戻る