GNU BC: Cum este util modulul (%) cu o scară diferită de 0?

Aceasta este o întrebare auto-răspuns , cercetarea care este rezonabilă pentru a pune o întrebare merge în partea de răspuns, vă rugăm să nu votați în jos pentru că credeți că nu am cercetat suficient pentru un răspuns. Mulțumiri. În orice caz, nu există nicio descriere (pe care o pot găsi) a acestei caracteristici a bc în acest site.

Când se utilizează bc, % este revendicat pentru a calcula „restul” și da, funcționează pentru numere întregi și când scara este zero :

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

Dar nu reușește să dea„ restul întreg ”dacă scara nu este zero:

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

De ce (sau cum) este utilă această definiție a % modul?

Răspuns

Operatorul % este clar definit în bc manual ca [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) } 

Presupunând că max a fost definit ca:

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

Cum este utilă această lungă definiție?

  1. Restul întregului .
    Voi afișa atât și rezultatele operatorului % pentru a demonstra că sunt echivalente pentru unele dintre următoarele operațiuni.

    Dacă numerele sunt întregi și scala este setată la 0, este funcția restului întregului.

    $ 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 

Acest lucru nu este același lucru cu funcția mod matematică. Voi rezolva asta mai jos.

  1. Restul zecimal.
    Dacă numărul n este un număr zecimal mai lung și modificăm scala, obținem:

    $ 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 

    Rețineți că aici, primele 3 cifre zecimale au fost eliminate și restul dat provine din a patra cifră zecimală.

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

    Aceasta arată că restul este mai versatilă prin această definiție.

Acum este: restul după valoarea scării.

  1. Schimbarea scării Schimbarea scării este necesară deoarece numărul d (divizor) poate avea mai multe cifre zecimale decât n. În acest caz, sunt necesare mai multe zecimale pentru a avea un rezultat mai precis din împărțire:

    $ 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 

    Și, dacă scala se schimbă 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 

    După cum se poate vedea mai sus, valoarea scalei se modifică pentru a prezenta un rezultat destul de precis al divizării pentru orice valoare a n, d și scale.

I” Vom presupune că, prin comparația dintre internalmod și operatorul %, ambele s-au dovedit a fi echivalente.

  1. Confuzie . Aveți grijă, deoarece jocul cu valoarea d poate deveni confuz:

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

    Și:

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

    Adică: valoarea d (peste 1) va modifica efectul valorii setului de scară.

Probabil, pentru valori d diferite de 1 ar trebui să utilizați scale = 0 (cu excepția cazului în care știți cu adevărat ce faceți).

  1. Math mod .
    Deoarece suntem luând o astfel de scufundare profundă în funcțiile mod, probabil că ar trebui să clarificăm efectul real al % în bc. Operatorul % din bc utilizează o „divizare trunchiată”. Unul care se rotunjește către 0. Acest lucru este important pentru valorile negative ale n și / sau d:

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

    Semnul restului urmează semnul dividend.

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

    În timp ce este corect math mod ar trebui să dea un rest întotdeauna pozitiv .

    Pentru a obține acea funcție mod (întreg), utilizați:

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

    Și (apoi) acest lucru va funcționa:

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

[a]

expr% expr
Rezultatul expresiei este „restul” și este calculat în cele ce urmează cale. Pentru a calcula un% b, mai întâi a / b este calculat pentru a scala cifre.Acest rezultat este folosit pentru a calcula a- (a / b) * b la scara maximului scalei + scalei (b) și scalei (a).
Dacă scala este setată la zero și ambele expresii sunt numere întregi această expresie este funcția restului întregului.


Pentru codul bc care urmează punctului în care această notă de subsol a fost introdus pentru a funcționa corect, definiți un alias ca:

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

Și creați un fișier numit $HOME/.func.bc care conține ( cel puțin):

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

O funcție mod pentru orice număr (întreg sau nu) poate fi definită ca:

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

Această definiție este perfect validă și corectă de regulile matematice, cu toate acestea, poate deveni destul de confuză atunci când încercați să o aplicați în cazuri reale, spunând doar.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *