Как преобразовать число с плавающей запятой в отношение?

Похожий, но более надежный вариант подхода @RubberStamp mail, при котором мы отправляем электронное письмо в формате HTML внутри

, чтобы почтовые клиенты отображали его как -в фиксированном -ширина шрифта (требуется GNUrecode):
#! /bin/sh -
PATH=$PATH:/usr/sbin:/usr/lib # adding common locations of sendmail
export PATH

{
  printf '%s\n' \
    'To: email' \
    'Subject: test' \
    'MIME-Version: 1.0' \
    'Content-Type: text/html' \
    '' \
    '
'
  /path/to/executable-script/executable-script.sh status |
    recode..html
  printf '
\n' } | sendmail -t -oi

Если recodeне установлен и не может быть установлен, а в вашей системе есть perl-модуль HTML::Entities, вы можете заменить recode..htmlна:

perl -Mopen=locale -MHTML::Entities -pe '$_=encode_entities$_'

3
21.04.2020, 19:34
2 ответа

16/9 не 1,778. Это (до 50 мест):

1.777777777777777777777777777777777777777777777777

И наоборот, 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. Это говорит о том, что существует семейство приближений, основанных на непрерывных дробях. Итак, мой второй алгоритм — найти общий метод построения бесконечного ряда, сходящегося к заданному значению. Но только если мне приходилось иметь дело с серьезным количеством дел.

1
19.03.2021, 02:27

Педантично это или нет, если наш человек смотрит только на 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
2
19.03.2021, 02:27

Теги

Похожие вопросы