GNU BC: Come è utile il “modulo” (%) con scala diversa da 0?

Questa è una auto-risposta , la ricerca per cui è ragionevole porre una domanda va nella parte relativa alla risposta. Per favore, non sottoporre a downvote perché ritieni che non abbia studiato abbastanza per una risposta. Grazie. In ogni caso, non esiste una descrizione (che posso trovare) di questa caratteristica di bc in questo sito.

Quando si utilizza bc, il % calcola il “resto” e sì, funziona per i numeri interi e quando la scala è zero :

$ bc <<<" scale=0; 27 % 7 " 6 

Ma non fornisce il” resto intero “se la scala non è zero:

$ bc <<<" scale=10; 27 % 7 " .0000000003 

Perché (o come) questa definizione del % modulo è utile?

Risposta

Loperatore % è chiaramente definito in bc manual come [a] :

# 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) } 

Supponendo che max sia stato definito come:

define max(x,y){ if(x>y){return(x)};return(y) } 

In che modo è utile questa lunga definizione?

  1. Intero resto .
    Mostrerò entrambi i e loperatore % dimostrano che sono equivalenti per alcune delle operazioni successive.

    Se i numeri sono interi, e scale è impostato su 0, è la funzione resto intero.

    $ 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 

Non è la stessa della funzione math mod. Lo risolverò di seguito.

  1. Resto decimale.
    Se il numero n è un numero decimale più lungo e modifichiamo la scala, otteniamo:

    $ 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 

    Tieni presente che qui, le prime 3 cifre decimali sono state rimosse e il resto fornito è dalla quarta cifra decimale.

    $ bc <<<"n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d; print a," ",b,"\n"" .000000089 .000000089 

    Ciò mostra che il resto è reso più versatile da questa definizione.

Ora è: il resto dopo il valore della scala.

  1. Modifica della scala Il cambio di scala è necessario perché il numero d (divisore) può contenere più cifre decimali di n. In tal caso, sono necessari più decimali per ottenere un risultato più preciso dalla divisione:

    $ 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 

    E, se la scala cambia e:

    $ 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 

    Come si può vedere sopra, il valore della scala cambia per presentare un risultato ragionevolmente preciso della divisione per qualsiasi valore di n, d e scale.

I” Assumerò che dal confronto tra loperatore internalmod e loperatore % sia stato dimostrato che entrambi sono equivalenti.

  1. Confusione . Fai attenzione perché giocare con il valore di d può creare confusione:

    $ bc <<<"n=17.123456789; d=10; scale=3; a=n%d; print a," ",scale(a),"\n"" .003456789 9 

    E:

    $ bc <<<"n=17.123456789; d=1000; scale=3; a=n%d; print a," ",scale(a),"\n"" .123456789 9 

    Ovvero: il valore di d (sopra 1) modificherà leffetto del valore di scala impostato.

Probabilmente, per valori di d diversi da 1 dovresti usare scale = 0 (a meno che tu non sappia veramente cosa stai facendo).

  1. Math mod .
    Dato che siamo Facendo un tuffo così profondo nelle funzioni mod, probabilmente dovremmo chiarire il vero effetto di % in bc. Loperatore % in bc utilizza una “divisione di troncamento”. Uno che arrotonda verso 0. Questo è importante per i valori negativi di n e / o d:

    $ bc <<<"scale=0; n=13; d=7; n%d; " 6 $ bc <<<"scale=0; n=13; d=-7; n%d; " 6 

    Il segno del resto segue il segno del dividend.

    $ bc <<<"scale=0; n=-13; d=7; n%d; " -6 $ bc <<<"scale=0; n=-13; d=-7; n%d; " -6 

    Mentre un corretto math mod dovrebbe dare a un resto sempre positivo .

    Per ottenere quella funzione mod (intera), usa:

    # 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)) } 

    E (quindi) funzionerà:

    $ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)" 6.123456789 

[a]

expr% expr
Il risultato dellespressione è il “resto” ed è calcolato come segue modo. Per calcolare a% b, prima a / b viene calcolato per scalare le cifre.Questo risultato viene utilizzato per calcolare a- (a / b) * b sulla scala del massimo di scale + scale (b) e scale (a).
Se scale è impostato su zero ed entrambe le espressioni sono numeri interi, questa espressione è la funzione di resto del numero intero.


Per il codice bc che segue il punto in cui questa nota è stato introdotto per funzionare correttamente, definire un alias come:

$ alias bc="bc -l "$HOME/.func.bc"" 

E creare un file denominato $HOME/.func.bc che contiene ( almeno):

# 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(x)};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){x=-1};if(x>0){x=1};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)) } 

Una funzione mod per qualsiasi numero (intero o no) può essere definita come:

# 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){y-=1};scale=os;return(y) }; 

Questa definizione è perfettamente valida e corretta secondo le regole matematiche, tuttavia, può creare confusione quando si cerca di applicarla in casi reali, solo dicendo.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *