GNU BC: Hvordan er “modulo” (%) med annen skala enn 0 nyttig?

Dette er et selvsvaret spørsmål, forskningen som er rimelig å be om et spørsmål, går inn i svardelen, vær så snill å ikke nedstemme fordi du mener at jeg ikke har undersøkt nok for et svar. Takk. I alle fall er det ingen beskrivelse (som jeg kan finne) av denne egenskapen til bc på dette nettstedet.

Når du bruker bc, % operatøren hevdes å beregne «resten», og ja, det fungerer for heltall og når skalaen er null :

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

Men det gir ikke» heltallet resten «hvis skalaen ikke er null:

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

Hvorfor (eller hvordan) er denne definisjonen av % modulo nyttig?

Svar

% operatoren er tydelig definert 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) } 

Forutsatt at max er definert som:

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

Hvordan er den lange definisjonen nyttig?

  1. Heltall resten .
    I «vil vise både internalmod -funksjonen og % -operatørresultatene viser at de er ekvivalente for noen av de neste operasjonene.

    Hvis tallene er heltall, og skala er satt til 0, det er funksjonen for resten av hele tallet.

    $ 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 er ikke det samme som matte mod-funksjonen. Jeg løser det nedenfor.

  1. Desimal rest.
    Hvis tallet n er et lengre desimaltall, og vi endrer skalaen, 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 

    Merk at her ble de tre første desimaltegnene fjernet, og resten som er gitt er fra det fjerde desimaltallet.

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

    Det viser at resten blir gjort mer allsidig av den definisjonen.

Nå er det: resten etter verdien på skalaen.

  1. Skalaendring Skalaendring er nødvendig fordi tallet d (divisor) kan ha flere desimaltegn enn n. flere desimaler er nødvendig for å få et mer presist resultat fra divisjonen:

    $ 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 

    Og hvis skalaen endres 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 det kan sees ovenfor, endres skalaverdien for å presentere et rimelig presist resultat av delingen for en hvilken som helst verdi på n, d og scale.

I» Jeg antar at ved sammenligningen mellom internalmod og % operatøren begge har vist seg å være ekvivalente.

  1. Forvirring . Vær forsiktig fordi det å spille med verdien d kan bli forvirrende:

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

    Og:

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

    Det vil si: verdien til d (over 1) vil endre effekten av verdien av skalasettet.

Sannsynligvis, for verdier på d som er forskjellige enn 1, bør du bruke skala = 0 (med mindre du virkelig vet hva du gjør).

  1. Math mod .
    Siden vi er tar vi et så dypt dykk inn i mod-funksjoner, bør vi sannsynligvis avklare den virkelige effekten av % i bc. % operatøren i bc bruker en «avkuttende divisjon». En som runder mot 0. Det er viktig for negative verdier av både n og / eller d:

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

    Tegn for resten følger tegnet på dividend.

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

    Mens det er riktig matematikk mod skal gi en alltid positiv rest .

    For å få den (heltall) mod-funksjonen, bruk:

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

    Og (da) vil dette fungere:

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

[a]

expr% expr
Resultatet av uttrykket er «resten» og det beregnes i det følgende vei. For å beregne a% b beregnes først a / b for å skalere sifre.Resultatet blir brukt til å beregne a- (a / b) * b til skalaen for maksimal skala + skala (b) og skala (a).
Hvis skala er satt til null og begge uttrykkene er heltall, vil dette uttrykket er resten av funksjonen.


For bc -koden som følger punktet der denne fotnoten er ble introdusert for å fungere riktig, definer et alias som:

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

Og opprett en fil med navnet $HOME/.func.bc som inneholder ( i det minste):

# 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 mod-funksjon for et hvilket som helst tall (heltall eller ikke) kan defineres 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) }; 

Denne definisjonen er helt gyldig og korrekt av matteregler, men den kan bli ganske forvirrende når du prøver å bruke den i virkelige tilfeller, bare å si.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *