%
Оператор четко определено в bc
руководстве как [а] :
# Internal % operator definition: define internalmod(n,d,s) { auto r,oldscale; oldscale=scale; r=n/d; s=max(s+scale(d),scale(n)); scale=s; r = n-(r)*d; scale=oldscale; return(r) }
Предполагая max
, был определен как:
define max(x,y){ if(x>y);return(y) }
Чем полезно это длинное определение?
1. Целочисленный остаток .
Я буду использовать как internalmod
функцию, так и %
оператор, чтобы показать, что они эквивалентны для некоторых операций ниже
Если числа целые и масштаб установлен на 0, это целочисленная функция остатка.
$ bc <<<'n=17; d=3; scale=0; a=internalmod(n,d,scale); b=n%d; print a," ",b,"\n"' 2 2 $ bc <<<'n=17; d=6; scale=0; a=internalmod(n,d,scale); b=n%d; print a," ",b,"\n"' 5 5
Это не то же самое, что математическая мод-функция. Я решу это ниже.
2. Десятичный остаток.
Если число n
является более длинным десятичным числом, и мы изменяем масштаб, мы получаем:
$ bc <<<'n=17.123456789;d=1; scale=0 ;a=internalmod(n,d,scale);b=n%d;print a," ",b,"\n"' .123456789 .123456789 $ bc <<<'n=17.123456789;d=1; scale=3 ;a=internalmod(n,d,scale);b=n%d;print a," ",b,"\n"' .000456789 .000456789
Обратите внимание, что здесь первые 3 десятичных знака были удалены, а остаток от четвертого десятичного знака.
$ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;print a," ",b,"\n"' .000000089 .000000089
Это показывает, что остальное сделано более универсальным по этому определению.
3. Изменение масштаба Изменение масштаба требуется, потому что число d
(делитель) может иметь больше десятичных цифр, чем n
. В этом случае требуется больше десятичных знаков, чтобы получить более точный результат от деления:
$ bc <<<'n=17.123456789; d=1.00000000001; scale=0; a=internalmod(n,d,scale); b=n%d; print a," ",scale(a)," -- ", b," ",scale(b),"\n"' .12345678883 11 -- .12345678883 11
И, если масштаб меняется:
$ bc <<<'n=17.123456789; d=1.00000000001; scale=5; a=internalmod(n,d,scale); b=n%d; print a," ",scale(a)," -- ", b," ",scale(b),"\n"' .0000067888287655 16 -- .0000067888287655 16
Как видно выше, масштабное значение увеличивается, чтобы представить достаточно точный результат деления для любого значения n
, d
и scale
.
Я предполагаю, что по сравнению между internalmod
и с %
оператором, как было доказано, чтобы быть эквивалентными.
4. Путаница . Будьте осторожны, потому что игра со значением d
может сбить с толку:
$ bc <<<'n=17.123456789; d=10; scale=3; a=n%d; print a," ",scale(a),"\n"' .003456789 9
А также:
$ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d; print a," ",scale(a),"\n"' .123456789 9
То есть: значение d
(выше 1) изменит эффект значения установленного масштаба.
Вероятно, для значений, d
отличных от 1, вы должны использовать scale = 0 (если вы действительно не знаете, что делаете).
5. Математический мод .
Поскольку мы принимаем такое глубокое погружение в мод функций, мы, вероятно, следует уточнить реальный эффект %
в bc
. %
Оператор Ьс использует «усечение деления». Тот, который округляет в сторону 0
. Это важно для отрицательных значений обоих n
и / или d
:
$ bc <<<'scale=0; n=13; d=7; n%d; ' 6 $ bc <<<'scale=0; n=13; d=-7; n%d; ' 6
Знак остатка следует за знаком dividend
.
$ bc <<<'scale=0; n=-13; d=7; n%d; ' -6 $ bc <<<'scale=0; n=-13; d=-7; n%d; ' -6
Хотя правильный математический мод должен давать всегда положительный остаток .
Чтобы получить эту (целочисленную) функцию мода, используйте:
# Module with an always positive remainder (euclid division). define modeuclid(x,div) { if(div!=int(div)){ "error: divisor should be an integer ";return(0)}; return(x - div*int(x/div)) }
И это будет работать:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)" 6.123456789
[А]
expr% expr
Результатом выражения является «остаток», который вычисляется следующим образом. Чтобы вычислить% b, сначала вычисляется a / b для масштабирования цифр. Этот результат используется для вычисления a- (a / b) * b по шкале максимума scale + scale (b) и scale (a).
Если масштаб установлен на ноль, и оба выражения являются целыми числами, это выражение является функцией целочисленного остатка.
Для bc
кода, который следует за точкой, где эта сноска была введена для правильной работы, определите псевдоним как:
$ alias bc='bc -l "$HOME/.func.bc"'
И создайте файл с именем, $HOME/.func.bc
который содержит (как минимум):
# Internal % operator definition: define internalmod(n,d,s) { auto r,oldscale; oldscale=scale; r=n/d; s=max(s+scale(d),scale(n)); scale=s; r = n-(r)*d; scale=oldscale; return(r) } # Max function define max(x,y){ if(x>y);return(y) } # Integer part of a number toward 0: -1.99 -> -1, 0.99 -> 0 define int(x) { auto os;os=scale;scale=0; x=sgn(x)*abs(x)/1;scale=os;return(x) } define sgn (x) { if (x<0);if(x>0);return(x) }; define abs (x) { if (x<0) x=-x; return x }; # Module with an always positive remainder (euclid division). define modeuclid(x,div) { if(div!=int(div)){ "error: divisor should be an integer ";return(0)}; return(x - div*int(x/div)) }
Мод-функция для любого числа (целое или нет) может быть определена как:
# Module with an always positive remainder (Euclid division). define modeuclid(x,div) { div=abs(div);return(x - div*floor(x/div)) } # Round down to integer below x (toward -inf). define floor (x) { auto os,y;os=scale;scale=0; y=x/1;if(y>x);scale=os;return(y) };
Это определение совершенно правильно и правильно по математическим правилам, однако, оно может стать довольно запутанным, когда вы пытаетесь применить его в реальных случаях, просто говоря.