浮動小数点数を比率に変換するには?

浮動小数点数を比率に変換するには?

浮動小数点数を比率または分数に変換したいと思います。

Pythonと同様に浮動小数点を1.778比率に変換する16:9か、bashに変換するオプションはありますか?16/9噴水モジュールFraction(1.778).limit_denominator(100))。

答え1

awk -v prec=0.001 -v max=2000 '
   function fract(n, k, kr, d){
       for(k=n;k<max;k+=n){
           kr=int(k+.5); d=kr-k; if(d<0)d=-d;
           if(d<prec){return kr"/"k/n}
       }
       return n" ??"
   }
   BEGIN{for(i=1;i<ARGC;i++)print fract(ARGV[i])}
' 3.1415926535 1.77777777 0.333333 2.71828 1.61803398
355/113
16/9
1/3
1264/465
987/610

繰り返し加算の代わりに乗算するとより正確になりますが、これが遅くなる可能性があります。

awk -v prec=0.00005 -v max=20000 '
   function fract(n, k, kr, kf, d){
       for(k=1;k<max;k++){
           kf=n*k; kr=int(kf+.5); d=kr-kf; if(d<0)d=-d;
           if(d<prec){return kr"/"k}
       }
       return n" ??"
   }
   BEGIN{for(i=1;i<ARGC;i++)print fract(ARGV[i])}
' 3.14159265358979323846 1.7777777 0.33333333 2.7182818 1.61803398
355/113
16/9
1/3
34109/12548
24476/15127

max「調整可能」は実際にはmax_numerator / orig_num2番目のバージョンにあります)。

答え2

賢いかどうかにかかわらず、私たちの人々が小数点以下の3桁までの精度にのみ興味があるなら...

古いawkハンマーを壊し、同じように古い昔のハンマーを作る最低分母は、有名なアルゴリズムの代わりに最も低いエラーと分母を見つけます。

echo "1.778" | awk 'BEGIN{en=1; de=101; er=1}{
    for (d=100; d>=1; d--) {n=int(d*$1); e=n/d-$1; e=e*e;
    if (e<=er && d<de){er=e; de=d; en=n}}
    print en":"de, en/de}'

だから...

16:9 1.77778

bashこのような操作は、適切なスコア乗数を使用して純粋に実行することもできます。

私たちが競争したいなら

real    0m0.004s
user    0m0.001s
sys     0m0.003s

答え3

16/9は1.778ではありません。 (50箇所まで):

1.7777777777777777777777777777777777777777777777777

代わりに、16.002/9は実際には正確に1.778です。

したがって、正確に16/9の数字を持つことは事実上不可能です(少なくとも10進数ではなく、桁数が制限されています)。

近似で許容可能な精度レベルを定義する必要があります。

私の最初の無差別代入アルゴリズムは、AとBで二重ループを試み、A / Bを計算してから(おそらく)6桁まで正しいときに停止することでした。

シェルスクリプト:

#! /bin/bash

function Ratio {

AWK='
function Ratio (min, max, Local, a, b, q) {
    for (a = 1; a < 1e6; a++) {
        for (b = 1; b <= a; b++) {
            q = (a / b);
            if (min < q && q < max) {
                printf ("Ratio %d / %d is %.12f\n", a, b, q);
                return;
            }
        }
    }
}
{ Ratio( $1, $2); }
'   
    awk "${AWK}"
}

    {
        echo 2.8897 2.8899
        echo 1.77777777777 1.77777777778 
        echo 3.14159292 3.14159293
    } | Ratio

アプリケーションは次のとおりです。

paul $ time ./Ratio
Ratio 341 / 118 is 2.889830508475
Ratio 16 / 9 is 1.777777777778
Ratio 355 / 113 is 3.141592920354

real    0m0.085s
user    0m0.072s
sys     0m0.012s

当然、1.778(> 1)から始めると、A <= Bの場合を確認する必要はありません。これは、連続分数に基づく近似系列があることを示唆している。だから私の2番目のアルゴリズムは、指定された値に収束する無限系列を構築する一般的な方法を見つけることです。ただし、多くの場合を処理する必要がある場合にのみ該当します。

関連情報