bash, bc по модулю не работает с флагом -l

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

Без каких-либо флагов bc <<< "3%5", конечно же, возвращает 3.

Но с bc -l (загружает математическую библиотеку, чтобы я мог вычислять логарифмы) любое вычисление a%b возвращает 0, где a и b могут быть любыми числами, кроме 0.

Что творится?


person Saad Attieh    schedule 14.12.2014    source источник


Ответы (5)


Потому что из мануала:

   expr % expr
          The result of the expression is the "remainder" and it  is  com‐
          puted  in  the following way.  To compute a%b, first a/b is com‐
          puted to scale digits.  That result is used to compute a-(a/b)*b
          to  the scale of the maximum of scale+scale(b) and scale(a).  If
          scale is set to zero and  both  expressions  are  integers  this
          expression is the integer remainder function.

Когда вы запускаете bc с флагом -l, scale устанавливается на 20. Чтобы исправить это:

bc -l <<< "oldscale=scale; scale=0; 3%5; scale=oldscale; l(2)"

Сначала мы сохраняем scale в переменной oldscale, затем присваиваем scale значение 0 для выполнения некоторых арифметических операций, а для вычисления ln возвращаем старое значение scale. Это выведет:

3
.69314718055994530941

как хотел.

person gniourf_gniourf    schedule 14.12.2014

Согласно инструкции bc,

   expr % expr
          The result of the expression is the "remainder" and it is computed 
          in the following way.  To compute a%b, first a/b is computed to
          scale digits.   That  result  is used to compute a-(a/b)*b to the 
          scale of the maximum of scale+scale(b) and scale(a).  If scale is
          set to zero and both expressions are integers this expression is 
          the integer remainder function.

Итак, что происходит, так это то, что он пытается оценить a-(a/b)*b, используя текущие настройки scale. По умолчанию scale равно 0, поэтому вы получаете остаток. Когда вы запускаете bc -l, вы получаете scale=20, а выражение a-(a/b)*b оценивается как ноль при использовании 20 дробных цифр.

Чтобы увидеть, как это работает, попробуйте другие дроби:

$ bc -l
1%3
.00000000000000000001

Короче говоря, просто сравните три результата:

По умолчанию scale с включенным -l (20):

scale
20

3%5
0

1%4
0

Давайте установим scale в 1:

scale=1

3%5
0

1%4
.2

Или в ноль (по умолчанию без -l):

scale=0

3%5
3

1%4
1
person afenster    schedule 14.12.2014

Вы можете определить функцию, которая работает в математическом режиме, временно установив scale на ноль.

У меня bc такой псевдоним:

alias bc='bc -l ~/.bcrc'

Таким образом, ~/.bcrc оценивается перед любыми другими выражениями, поэтому вы можете определять функции в ~/.bcrc. Например, функция модуля:

define mod(x,y) { 
  tmp   = scale
  scale = 0
  ret   = x%y
  scale = tmp
  return ret
}

Теперь вы можете сделать это по модулю следующим образом:

echo 'mod(5,2)' | bc

Выход:

1
person Thor    schedule 16.06.2017

человек до н.э.:

Если bc вызывается с параметром -l, предварительно загружается математическая библиотека, а масштаб по умолчанию устанавливается равным 20.

Так что, возможно, вам следует установить масштаб на 0 :

#bc
scale=0
10%3
1
person mpiffault    schedule 14.12.2014

Для чего это стоит, когда я использую bc -l, у меня определены следующие функции:

define trunc(x)   {auto s; s=scale; scale=0; x=x/1; scale=s; return x}
define mod(x,y)   {return x-(y*trunc(x/y))}

Это должно дать вам правильную функцию MOD, сохраняя при этом вашу шкалу. Конечно, это не поможет, если по какой-то причине вам НЕОБХОДИМО использовать оператор %.

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

person Unbeliever    schedule 21.06.2018