GNU BC: Hur är ”modulo” (%) med annan skala än 0 användbar?

Detta är en självbesvarad fråga, den forskning som är rimlig att ställa en fråga finns i svaret, vänligen nedrösta inte eftersom du tror att jag inte har undersökt tillräckligt för ett svar. Tack. I vilket fall som helst finns det ingen beskrivning (som jag kan hitta) av denna egenskap hos bc på den här webbplatsen.

När du använder bc, % operatören påstås beräkna ”resten”, och ja, det fungerar för heltal och när -skalan är noll :

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

Men det går inte att ge” heltalsresten ”om skalan inte är noll:

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

Varför (eller hur) är denna definition av % modulo användbar?

Svar

% -operatören är tydligt definierad i bc manual som [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) } 

Förutsatt att max har definierats som:

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

Hur är den långa definitionen användbar?

  1. Resterande heltal .
    I ”kommer att visa både internalmod -funktionen och % -operatörens resultat för att bevisa att de är ekvivalenta för några av de nästa operationerna.

    Om siffrorna är heltal och skalan är inställd på 0, det är resten-funktionen.

    $ 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 

Det är inte samma sak som matematikmodfunktionen. Jag löser det nedan.

  1. Återstående decimal.
    Om siffran n är ett längre decimaltal och vi ändrar skalan får vi:

    $ 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 

    Observera att här, de tre första decimalsiffrorna togs bort och resten som anges är från den fjärde decimalsiffran.

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

    Det visar att resten görs mer mångsidig med den definitionen.

Nu är det: resten efter skalans värde.

  1. Skalförändring Ändring av skalan krävs eftersom siffran d (divisor) kan ha fler decimaler än n. fler decimaler behövs för att få ett mer exakt resultat från uppdelningen:

    $ 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 

    Och om skalan ändras 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 

    Som kan ses ovan ändras skalvärdet för att ge ett rimligt exakt resultat av uppdelningen för vilket värde som helst av n, d och scale.

I” Jag antar att både jämförelsen mellan internalmod och % operatören har visat sig vara ekvivalenta.

  1. Förvirring . Var försiktig för att spela med värdet på d kan bli förvirrande:

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

    Och:

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

    Det vill säga: värdet på d (ovanför 1) kommer att ändra effekten av värdet på skalan.

För värden d som är annorlunda än 1 bör du använda skalan = 0 (om du inte vet vad du gör).

  1. Math mod .
    Eftersom vi är tar vi ett sådant djupt dyk i modfunktioner, borde vi förmodligen klargöra den verkliga effekten av % i bc. % -operatören i bc använder en ”trunkerande division”. En som avrundar mot 0. Det är viktigt för negativa värden för både n och / eller d:

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

    Resterande tecken följer tecknet på dividend.

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

    Medan det är korrekt matematik mod ska ge en alltid positiv återstod .

    För att få den (heltal) modfunktionen, använd:

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

    Och (då) fungerar det:

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

[a]

expr% expr
Resultatet av uttrycket är ”resten” och det beräknas i följande sätt. För att beräkna a% b beräknas först a / b för att skala siffror.Resultatet används för att beräkna a- (a / b) * b till skalan för skalan + skalan (b) och skalan (a).
Om skalan är noll och båda uttrycken är heltal är detta uttryck är funktionen för återstoden av heltal.


För bc -koden som följer punkten där denna fotnot introducerades för att fungera korrekt, definiera ett alias som:

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

Och skapa en fil med namnet $HOME/.func.bc som innehåller ( åtminstone):

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

En modfunktion för valfritt tal (heltal eller inte) kan definieras som:

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

Denna definition är helt giltig och korrekt av matematiska regler, men det kan bli ganska förvirrande när man försöker tillämpa den i verkliga fall, bara säga.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *