みんなに優しく、解りやすくをモットーに開設しています。 以下のルールを守りみんなで助け合いましょう。
1.ファイルメーカーで解らない事があればここで質問して下さい。 何方でも、ご質問・ご回答お願いします。 (優しく回答しましょう)
You are not logged in.
Pages: 1
分数の計算をしたいのですが、分母の最大公約数を求めるにはどうしたら良いでしょうか?
Offline
アルゴリズムは、ユークリッドの互除法を検索してみてください。
再帰式で書くと、
Let(
[
$n1 = Max ( n1; n2);
$n2 = Min ( n1; n2);
$fnc =
"Case (
$n2 = 0 ; $n1 ;
Let (
[
$n0 = $n2 ;
$n2 = Mod ( $n1 ; $n2 ) ;
$n1 = $n0
] ;
Evaluate ( $fnc )
)
)"
] ;
Evaluate ( $fnc )
)
Last edited by Shin (2019-08-16 17:19:34)
Offline
Shin様 早速のご返答ありがとうございます。
言葉足らずで申し訳ありませんが、求めたい最大公約数の値が2つではなく、3個以上ある場合(今回は15個)はどうしたら良いでしょうか?
何に用いるかというと共有持ち分の表示に使いたいのです。
宜しくお願いします。
Offline
まず、n1 n2 で求め、その答えと n3 で求め、を繰り返せばいいです。
一気に求めるのでしたら、全ての数字を素因数分解して、それぞれを常用対数表示に置き換えて最小数を求めて、指数計算にもどす、という方法もあります。
素因数分解することはそんなに難しくはないのですが、その素数の指数を素数ごとに集計するのがちょっと面倒かもしれません。
素数をあらかじめ用意する形のサンプルを作ってみました。素数を20個用意しただけですので規模は小さいですが、計算は早いです。現実には、素数を大量に用意する必要があるので、ちょっと面倒かも。
https://www.dropbox.com/s/wd8m2u5kl8l2q … 2.zip?dl=0
Last edited by Shin (2019-08-17 17:26:27)
Offline
>#4『まず、n1 n2 で求め、その答えと n3 で求め、を繰り返せばいいです。』
その具体式は、(※ >#2ループ式を改造、2段ループ式に拡張して)
(ただし、この>#4「説明ロジックの真偽」については判断してません。)
Let(
[
//$n1=Max(n1;n2);
//$n2=Min(n1;n2);
$fnc=
"Case(
$n2=0; $n1;
Let(
[
$n0=$n2;
$n2=Mod($n1;$n2);
$n1=$n0
];
Evaluate($fnc)
)
)"
];
//Evaluate($fnc)
Let(
[
$nos=List(n1;n2;n3;n4;n5;n6;n7;n8;n9;n10;n11;n12;n13;n14;n15);
$i=0;
$res=GetValue($nos;1);
$loop=
"Case(
$i=ValueCount($nos); $res;
Let(
[
$i=$i+1;
$n1=Max($res*1; GetValue($nos;$i)*1);
$n2=Min($res*1; GetValue($nos;$i)*1);
$res=Evaluate($fnc)
];
Evaluate($loop)
)
)"
];
Evaluate($loop)
)
)
Last edited by Hiro (2019-08-17 15:36:05)
Offline
>#4「説明ロジックの真偽」の証明
各数字を素因数分解をした形にして、
Aˆa1 * Bˆb1 * Cˆc1, Aˆa2 * Bˆb2 * Cˆc2, Aˆa3 * Bˆb3 * Cˆc3
となっている時に、最大公約数は、Aˆmin(a1,a2,a3) * Bˆmin(b1,b2,b3) * Cˆmin(c1,c2.c3) です。
min(i,j,k) は、min(min(i,j) ,k) と必ず等しいので、上のロジックは正しいです。
Offline
Shin様、Hiro様、ご回答ありがとうございます。
とても昔の数学で習ったかも?な言葉が当方の理解に時間がかかりそうです。
以前にHiro様に教えて頂いた式の理解も及ばない状態での今回の事態に苦慮してまして・・
丸ごとコピーして使ってみようと思っています。
ドロップボックスはメンバー登録が必要?プレビューが出来ないみたいです。
Hiro様の記述式をコピーしたいのですが、
・線の引いてある所は要らない→//は不要ですか?必要ですか?行全体削除でOK?
・ドロップボックスに登録すればダウンロードできますか?
以上、お答えいただけると助かります。
Offline
>『線の引いてある所は要らない→//は不要ですか?必要ですか?行全体削除でOK?』
//はコメントアウト記号で、>#2オリジナル式の不用箇所、行全体削除でOKです。
>『ドロップボックスに登録すればダウンロードできますか?』
ドロップボックスの登録は無用です。画面の右上端にある「…」アイコンをクリック→表示メニューから「直接ダウンロード」をクリックでダウンロードできます。
Offline
項目数に一応制限の無い、1パスのシンプルな式です。最初の List() の項目を増やすことができます。
Let(
[
$tx = List ( n1; n2 ; n3 ) ;
$tx = SortValues ( UniqueValues ( ¶ & $tx ; 2 ) ; 2 );
$fnc =
"Case (
ValueCount ( $tx ) ≤ 2 ; GetValue ( $tx ; 2 ) ;
Let (
[
$md = Mod ( GetValue ( $tx ; ValueCount ( $tx ) ) ; GetValue ( $tx ; 2 ) ) ;
$tx = List ( LeftValues ( $tx ; ValueCount ( $tx ) - 1 ) ; Case ( $md ; $md ) ) ;
$tx = SortValues ( UniqueValues ( \¶ & $tx ; 2 ) ; 2 )
] ;
Evaluate ( $fnc )
)
)"
] ;
Evaluate ( $fnc )
)
Last edited by Shin (2019-08-20 15:26:34)
Offline
>#9Shinさん『項目数に一応制限の無い、1パスのシンプルな式です。最初の List() の項目を増やすことができます。』
成る程!ロジック的にシンプルかつより直感的アルゴリズムで素晴らしい式案ですネ。
(Value系の新機能、SortValues関数とUniqueValues関数が使えるのが前提ですが、効果絶大!)
Offline
Shin様、Hiro様、ご返答ありがとうございます。
・ロップボックスからのダウンロードは御指示頂いた通りで出来ました。→フィールドの中身はロックがかかって見れませんでした。
・//はコメントアウト記号で、>#2オリジナル式の不用箇所、行全体削除でOKです。→理解できたと思います。
・項目数に一応制限の無い、1パスのシンプルな式→Value系の新機能が僕のバージョンでは使えないので、お小遣い貯めて新バージョン出たら購入し、その際に使ってみます。
よって、目的は旧バージョンの為、達せられずですが、FMpro advanced14を使っている為と考え、最新であれば解決するものと考えます。よって解決としますね。
Offline
評価版でお試しください。
FM14 でも、式は長くなりますが、Max() , Min() と、Substitute() を使えば、同じロジックで式は作れますよ。(複数の改行の処理にがちょっと面倒ですが)
Offline
Hiroさんの式を試されましたか?
Offline
ソートしないでも常に先頭の2つを処理していれば、割り切れたときにリストが1つ減っていくので、うまくいっているように見えます。
Let(
[
$tx = List ( 10020; 240;210 ;60 ) ;
$fnc =
"Case (
ValueCount ( $tx ) ≤ 1 ; $tx + 0 ;
Let (
[
a = GetValue ( $tx ; 1 ) + 0 ;
b = GetValue ( $tx ; 2 ) + 0 ;
md = Mod ( Max ( a ; b ) ; Min ( a ; b ) ) ;
$tx = List ( Case ( md ; md ) ; Min ( a ; b ) ; RightValues ( $tx ; ValueCount ( $tx ) - 2 ) )
] ;
Evaluate ( $fnc )
)
)"
] ;
Evaluate ( $fnc )
)
この再起式には全体の文字数の制限があって、だいたい300回 loop を超えるとエラーになります。ですから、その回数を減らす工夫をしてあるのです。
提示されているものは、私が#4 に書いたアルゴリズムを、最初に実証した式とほぼ同じです。
ソートやユニーク処理は必須ではないのですが、計算回数(loopの深さ)が大きく変わり、通常2倍程度、最大5倍以上になることを確認しています。
ソートをせずに回数を減らすためには、各比較を、最大と最小で演算を行う事ですが、これもちょっと面倒な処理が発生します。重複が途中でも発生しなければ、これで loop はほぼ同じになりますが、重複があれば最大数倍程度になります。
Last edited by Shin (2019-08-28 14:18:37)
Offline
ところで、、
最大公約数を得てどうしたいのでしょう?
通分なら最小公倍数ですが。
不動産のことだと思いますが全くの門外漢で。。
Offline
互除法自体が相当効率がいいので、引数自体が150個もある、とかでないとなかなか限界には達しないと思います。計算の途中で最大公約数が1になれば、あとは引数1個あたり各1回で完了するし。
私も門外漢ですが、例えば全体が4000で、各人の持ち分が100,200,300...55,とかあって、それを100/4000でなく(最大公約数の5で割って)20/800などと表示したい、とかかな。
15もあると、よほど恣意的に全部の数字をある数字の倍数とかに設定してあるんでないと、大抵は最大公約数が1ということになりそうな...
例えば1~無限大から15個の整数をランダムに選んで、最大公約数が2であるためには全部が2の倍数である必要があるんで、1/2^15の確率(約3万)ですよね?
Pages: 1
[ Generated in 0.005 seconds, 9 queries executed - Memory usage: 559.2 KiB (Peak: 580.11 KiB) ]