부동 소수점 수를 비율로 변환하는 방법은 무엇입니까?

부동 소수점 수를 비율로 변환하는 방법은 무엇입니까?

부동 소수점 숫자를 비율이나 분수로 변환하고 싶습니다.

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_num두 번째 버전에 있습니다).

답변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.7777777777777777777777777777777777777777777777

대신 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인 경우를 확인할 필요가 없습니다. 이는 연속 분수를 기반으로 한 근사값 계열이 있음을 시사합니다. 그래서 나의 두 번째 알고리즘은 지정된 값으로 수렴하는 무한 계열을 구성하는 일반적인 방법을 찾는 것입니다. 하지만 많은 경우를 처리해야 하는 경우에만 해당됩니다.

관련 정보