Занимательная математика командной строки

  • Tutorial

Если вы пользователь Linux, Free/Open BSD или другой свободной ОС, есть вероятность, что интерфейс командной строки вам не чужд. В таком случае можно использовать командную оболочку для простых арифметических действий. Для этого не нужно устанавливать дополнительных программ, все уже есть в базовом наборе операционной системы. Они позволяют качественно заменить привычный калькулятор на столике счетовода.



bash калькулятор целочисленный


Арифметические операции с целочисленными в bash будут выглядеть так:


$((expression))
$(( n1+n2 ))
$(( n1/n2 ))
$(( n1*n2 ))
$(( n1-n2 ))

Например:


$ echo $((15+25))
$ 40

На man странице bash, в разделе ARITHMETIC EVALUATION вы можете ознакомиться с приоритетом исполнения действий операторов. И, кстати, можно получить тот же результат, используя команду expr целочисленное выражение, вместо подстановки с двойными скобками в командах вывода.


$ expr 15 + 25
$ 40

bc мэдскиллз


Целочисленные выражения это конечно хорошо, но как-то маловато даже для калькулятора. Благо в наборе есть еще bc — Си-подобный интерактивный интерпретатор. Не будем тратить время на сложение и вычитание, перейдем сразу к более интересным занятиям.


$ echo 7^7 |bc
823543

Это уже получше калькулятора, так как позволяет получить любое количество чисел в дробной части с помощью переменной scale. Остерегайтесь поддельных проприетарных версий bc, так как они поддерживают всего-лишь 99 знаков после запятой!


$ echo 'scale=30;sqrt(2)' | bc
1.414213562373095048801688724209

Еще 2 важные переменные: ibase и obase указывают на основание входящих и исходящих чисел.


$ echo 'ibase=16;obase=A;FF' | bc
255

Тут, кстати, есть засада. Посмотрите на эти два примера. Вроде бы пытаешься сделать то же самое, но результат разный. Вся суть в том, что в первом примере ibase=2, но сама obase=10 принимает значение 2 в силу того, что ibase определяет по базе obase и 10 становится равной 2. Чтобы разорвать этот круг, надо использовать hex.


$ echo 'ibase=2;obase=10;10' | bc
10
$ echo 'ibase=2;obase=A;10' | bc
2

При множественном возведении числа в степень важно расставить нужным образом скобки, ибо bc правоассоциативна и результат может быть не тот, на который вы рассчитывали.


$ echo '4^4^4' |bc
13407807929942597099574024998205846127479365820592393377723561443721\
76403007354697680187429816690342769003185818648605085375388281194656\
9946433649006084096
$ echo '(4^4)^4' |bc
4294967296

Помимо этих художеств, bc имеет еще интерактивный режим в котором пищит и все портит делает все то же самое, но уже напрямую, без конвейера. Ключ -q нужен, чтобы подавить гнушное приветствие.


$ bc -q
4^4^4
13407807929942597099574024998205846127479365820592393377723561443721\
76403007354697680187429816690342769003185818648605085375388281194656\
9946433649006084096
quit

Замер производительности процессора с bc


Много лун назад на одном популярном англоязычном форуме, ныне покойном, предложили гениально простой способ нагреть проц и посчитать его скорость в попугаях.


time echo "scale=5000; 4*a(1)" | bc -l -q

Мы подгружаем в bc математическую библиотеку опцией -l и просим выдать число π с точностью 5000 знаков после запятой. Мой результат вычисления на Intel(R) Core(TM) i5-4300U CPU @ 1.90GHz:


real    0m24.507s
user    0m24.490s
sys     0m0.000s

Подгружаемые математические функции
s (x) The sine of x, x is in radians.
c (x) The cosine of x, x is in radians.
a (x) The arctangent of x, arctangent returns radians.
l (x) The natural logarithm of x.
e (x) The exponential function of raising e to the value x.
j (n,x) The Bessel function of integer order n of x.

Скрипты bc


В bc можно, если очень нужно, определять функции и запускать скрипты. Определение функции имеет следующий синтаксис:


define name ( parameters ) { newline
    auto_list statement_list }

Определены условные операторы if и else, причем последний не обязательно использовать, а также заголовки цикла for и while. На Википедии можно просмотреть список математических операторов и сравнить с таковым в Си. А вот так выглядит расчет чисел Фибоначчи в bc.


#!/usr/bin/bc -q
define fibo(n) {
    if (x <= 2) return n;
    a = 0;
    b = 1;
    for (i = 1; i < n; i++) {
        c = a+b; a = b; b = c;
    }
    return c;
}
fibo(1000)
quit

Как ЯП bc не взлетел, однако, в качестве настольного калькулятора он более чем хорош.


awk: арифмометр и гадалка


Мне не часто доводилось пользоваться awk, поэтому каждый раз я с удивлением обнаруживаю новые возможности этой программы. Если нужно посчитать логарифмы или синусы, не спешите паниковать, man awk вам поможет. Вот так мы получили квадратный корень.


awk 'BEGIN{print sqrt(196)}'
14

А вот мы уже логарифмируем число π, 5000 знаков которого мы уже вычисляли с помощью bc.


awk 'BEGIN{print log(3.141592653589793238462643383279502884197169399375105820974944592307)}'
1.14473

Оглашаю полный список возможностей


atan2(y, x)   Return the arctangent of y/x in radians.
cos(expr)     Return the cosine of expr, which is in radians.
exp(expr)     The exponential function.
int(expr)     Truncate to integer.
log(expr)     The natural logarithm function.
rand()        Return a random number N, between 0 and 1, such that 0 ≤ N < 1.
sin(expr)     Return the sine of expr, which is in radians.
sqrt(expr)    Return the square root of expr.
srand([expr]) Use expr as the new seed for the random number generator.  If no expr is provided, use the time of day. Return the previous seed for the random number generator.

Иногда, хочется довериться судьбе и послать все на три буквы — awk. Вообще-то, это пример из книги издательства O'Reilly, имитирует бросание монетки, выдавая 2 разных события пить или не пить с одинаковой вероятностью.


#!/bin/bash
ans=`awk -vmin=0 -vmax=1 'BEGIN{srand(); print int(min+rand()*(max-min+1))}'`

if [ $ans -eq 0 ]; then
    echo "no"
else
    echo "yes"
fi

В заключение


В нашей математической мастерской.еще очень много разных программ и если тема взлетит, попробуем перейти в первую и высшую лигу математического ПО с открытыми исходниками.


I. Замена калькулятора


  1. Встроенные средства командной оболочки: арифметические подстановки bash.
  2. Программа GNU bc.
  3. Неформат — awk.

II. Таблицы


  1. OpenOffice / LibreOffice Calc.
  2. KDE KSpread.
  3. GNOME Gnumeric.
  4. Одиночные, например: GNU Oleo и другие.

III. Специализированные математические программы, уровень студент+


  1. GNU Ocatve.
  2. Scilab.
  3. Maxima.
  4. R.
  5. Sage.

IV. Языки программирования, математические библиотеки и среды


  1. Ansi C, библиотеки math.h, complex.h, GSL и другие товарищи.
  2. Java Scientific Library
  3. Python, библиотеки SciPy, NumPy, Sympy и другие товарищи.
  4. COBOL.
  5. Fortran.
  6. Intel Math Kernel Library (Intel MKL)
  7. AMD Accelerated Parallel Processing Math (APPLM)
  8. AMD Core Math Library (ACML)

Список, естественно не полный, поэтому заранее прошу прощение, если не указал чей-то излюбленный математический пакет или ЯП. Последняя группа — поистине разливанное море разнообразного и годного софта.


А вот и обещанный мэдскиллз вместе с ответом на вопрос из картинки. Источник.


diff -u <(seq -f '%03.0f' 0 999) <((bc <<<'scale = 3009; 1 / 998001' | tr -d '\\\n'; echo) | sed s/.// | fold -3)
Поделиться публикацией
Комментарии 40
    +1
    Бенчмарк на i7-5775c, линукс в виртуалбоксе на винде.

    real 0m19.454s
    user 0m19.420s
    sys 0m0.000s

    Антиоффтопик:
    То есть, bc позволяет оперировать только от 2 до 16-ричной системы?
    А есть простой способ переводить в произвольную систему, без программирования?
      0
      i5-4460 CPU @ 3.20GHz, ESXi 6, тест в двух виртуалках — Linux и FreeBSD
      Примерно двукратная разница, результат расчета одинаков.
      Наверное разные реализации bс, не думаю что от ОС так зависит.

      Debian 8.2:

      real 0m17.874s
      user 0m17.796s
      sys 0m0.000s

      FreeBSD 10.3-RELEASE:

      9.600u 0.047s 0:09.67 99.6% 40+167k 0+0io 0pf+0w
        0
        i7-4700, встроенный в Win10 Bash
        real 0m15.492s
        user 0m15.438s
        sys 0m0.016s
          0
          уточню:
          i7-4770 CPU @ 3.40GHz и загрузка лишь +14%.
          Точно не про «нагреть проц»
            0
            Скорее всего, данный код однопоточный.
            Запустите несколько потоков.
          +1
          А есть простой способ переводить в произвольную систему, без программирования?
          Есть. Делим с остатком на основание системы. Остаток записываем справа. С результатом повторяем операцию, пока число не кончится.

          19 в двоичной
          19/2=9, остаток 1
          9/2=4, остаток 1
          4/2 = 2, остаток 0
          2/2 =1, остаток 0
          1/2 = 0, остаток 1
          записываем это всё справа-налево — 10011

          19 в пятиричной
          19/5 = 3, остаток 4
          3/5 = 0, остаток 3
          записываем справа-налево — 34

          19 в 19-ричной
          19/19 = 1, остаток 0
          1/19 = 0, остаток 1
          записываем справа-налево — 10

          19 в любой системе с основанием больше 19
          19/Основание = 0, остаток 19
          считаем 19 буквами, (помним, что F — 15) получаем J
            0
            Это не совсем простой, я думал что-то типа
            echo «base=10; 12312313» | bc
            Но без ограничений.
            А тут все равно придется писать.
              0
              а, я протупил. я решил, что вы спрашиваете, как вручную переводить в любую систему :)
                0
                https://www.tools4noobs.com/online_tools/base_convert/
              +3

              Zsh позволяет использовать любую систему счисления с целочисленными основаниями от 2 до 36:


              % echo $(( [#36] 15#1078ABE ))
              36#70D7H

              Специально для 16‐ричной системы работает префикс 0x, для двоичной — 0b, других специальных префиксов нет (для 8‐ричной можно включить обычный 0755 == 493, но по‐умолчанию это отключено). Zsh также работает и с числами с плавающей точкой (но только в десятичной записи). Но zsh работает только с 64‐битными целыми и double, никакой длинной арифметики или чисел произвольной точности. Можно попросить zsh отделять каждые n разрядов, по‐умолчанию 3:


              % echo $(( [#_] 107825.17632 ))
              107_825.176_32
              % echo $(( [#_4] 107825.17632 ))
              10_7825.1763_2
              0
              real 0m19.366s
              user 0m19.337s
              sys 0m0.024s

              mbpro
              MacBook Pro, i7 2.7 GHz, 16 Gb 1600 MHz DDR3

              Но как бенчмарк не интересно: грузилось только 1 и 8 ядер
                +1
                При множественном возведении числа в степень важно расставить нужным образом скобки, а то программа сама решит как лучше группировать.

                Чушь. Программа ничего не группирует, она просто делает то, что вы скажете. В следующем примере вы приказываете ей посчитать image4^4^4, и она так и делает.

                  –1

                  В программе забит приоритет и ассоциативность операторов, что превращает 4^4^4 в 4^(4^4). Такое вполне правильно считать «группировкой».

                    +3

                    А ещё в программу заложены правила записи числ цифрами и сложения чисел. Значит ли это, что при сложении чисел важно правильно записать исходные числа (ну скажем, не вводить 3+3, если хочешь сложить 2 и 2), а то программа сама решит как лучше складывать числа?

                      0

                      Во всех случаях программа «сама решает» в соответствии с заложенными в неё правилами. Я отвечал на ваше «ничего не группирует» — ассоциативность операторов определяет группировку и говорить так не менее некорректно.

                  +1

                  Из консоли считаю в node, просто запускаю и пишу выражение.
                  В gnome3 при установленном калькуляторе, можно считать прямо в строке поиска приложений.

                    +2
                    И в KDE тоже.
                      0
                      В Плазме или 4-й версии?
                        0
                        В 4-й точно считает, в строке которая по Alt+F2 вызывается. Очень удобно, не знал до этого и всегда в консоли считал :)
                      0
                      Во время чтения интернета для этой цели удобно использовать F12.
                      0
                      real 0m23.759s
                      user 0m23.547s
                      sys 0m0.016s
                      i5-2410M 2.30GHz
                      ubuntu bash on windows
                        +5
                        ipython в этом плане, наверное, лучше)
                          0
                          О, а я ghci использую.
                          +1
                          >$ expr 15+25

                          Пробелы пропущены, должно быть

                          $ expr 15 + 25
                            0
                            Вы правы, сейчас исправлю.

                            $ expr 15+25
                            $ 15+25
                            +3
                            Я в Windows вместо калькулятора использую python из командной строки
                              +2
                              echo 'ibase=2;obase=10;10' | bc
                              10

                              Из общих соображений кажется естественным вначале задавать obase в привычной системе, потом ibase. Я так попробовал, и оно работает ожидаемым образом:


                              echo 'obase=10;ibase=2;10' | bc
                              2

                                0
                                Класс!
                                $ echo 'ibase=2;obase=10;10' | bc
                                $ 10
                                $ echo 'obase=10;ibase=2;10' | bc
                                $ 2
                                
                                  0

                                  Развращенный идеей функциональной чистоты, которая из первобытных функциональных языков проникла в почти во все современные, народ уже начал было забывать ужасы императивщины и потерял страх перед побочными эффектами.


                                  ibase=2;obase=10;

                                  — здесь мне тоже хочется увидеть такой смысл:


                                  (ibase,obase)=(2,10)

                                  но в тех присваиваниях притаился побочный эффект.

                                0
                                Для этого не нужно устанавливать дополнительных программ, все уже есть в базовом наборе операционной системы.

                                В Arch по умолчанию нет bc.

                                  –1
                                  Это происки злой математички из 8-«Б» чтобы дети устно учились считать…
                                    +1
                                    Да и в Debian тоже.
                                    –1
                                    Еще существует консольный калькулятор apcalc.
                                      +1
                                      Единственное, что в bc раздражает, — это скудность математической библиотеки. Например, возведение в дробную степень отсутствует:
                                      $ echo '2^1.5' | bc -l
                                      Runtime warning (func=(main), adr=9): non-zero scale in exponent
                                      2

                                      Приходится извращаться с помощью экспоненты и логарифма, что не очень удобно:
                                      $ echo 'e(l(2)*1.5)' | bc -l
                                      2.82842712474619009755

                                      Или какой-нибудь арккосинус если нужно посчитать, приходится использовать арктангенс.
                                        0
                                        Виндовый CMD (а если точнее batch) тоже немного могёт в расчёты. Имеются: сложение, вычитание, умножение и деление (целочисленное, остаток подавляется). Например:
                                        set /a result=15+25
                                        echo %result%
                                        Стоит отметить, если не в скриптах пилить, то результат выдаст и первая строчка. Кроме того, учитывая тот факт, что приличная часть народу на линуксах использует wine, то сей метод хоть и бессмыслен, но всё же имеет место быть.
                                          0
                                          про bc рассказывается в книге «UNIX and Linux System Administration Handbook, 4th Edition» в вводной про сети. там же — про ipcalc, для расчета сетевых адресов и масок подсетей.
                                          про GHCi выше уже сказали, познакомился, когда пытался в haskell
                                          насчет таблиц и графиков, пользуем SigmaPlot
                                            +1
                                            Использую calc (пакет в Ubuntu — apcalc, в Arch — calc). В отличии от bc имеет более очевидный синтаксис и терпим к нему (не нужно следить за пробелами между частами выражения, «25+ 4 -6» = 23), фактически может использоваться как скриптовой язык (!) через #!/usr/bin/calc. Жаль, его нет в дефолтной поставке.
                                            А в раздел «математические среды», возможно, стоит добавить RStudio.
                                              –1
                                              В PowerShell арифметика в естественном виде доступна сразу. Я очень рад, что он портирован под Linux, очень удобно.
                                              Сам все еще часто пользуюсь bc или ghci (когда надо что-то нетривиальное со строками или списками посчитать), реже awk, если попалась какая-то таблица, а дочку пытаюсь приучить к R (она сопротивляется и пользуется обычным микрокалькулятором, даже не программируемым).
                                                +1
                                                Пример с потерей числа интересный, спасибо.
                                                Понадобилось какое-то время, чтобы понять, о чём речь и что к чему, особенно если пропустить ссылку на «источник» :)
                                                  0
                                                  real 0m50.958s
                                                  user 0m50.952s
                                                  sys 0m0.000s

                                                  model name: Intel® Pentium® 4 CPU 2.80GHz
                                                  cpu MHz: 2798.580
                                                  cache size: 1024 KB

                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                  Самое читаемое