Dit is een zelfbeantwoorde vraag, het onderzoek dat redelijk is om voor een vraag te stellen, gaat in het antwoordgedeelte. Gelieve niet naar beneden te stemmen omdat u denkt dat ik niet genoeg onderzoek heb gedaan voor een antwoord. Bedankt. In elk geval is er geen beschrijving (die ik kan vinden) van deze eigenschap van bc op deze site.
Bij gebruik van bc
, de %
operator berekent de “rest”, en ja, het werkt voor gehele getallen en wanneer de schaal nul is :
$ bc <<<" scale=0; 27 % 7 " 6
Maar het geeft geen” integer rest “als de schaal niet nul is:
$ bc <<<" scale=10; 27 % 7 " .0000000003
Waarom (of hoe) is deze definitie van de %
modulo nuttig?
Antwoord
De %
operator is duidelijk gedefinieerd in de bc
handleiding als [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) }
Ervan uitgaande dat max
is gedefinieerd als:
define max(x,y){ if(x>y){return(x)};return(y) }
Hoe is die lange definitie bruikbaar?
-
Geheel getal rest .
Ik “zal beideinternalmod
-functie en de%
-operatieresultaten om te bewijzen dat ze equivalent zijn voor enkele van de volgende bewerkingen.Als de getallen gehele getallen zijn, en schaal is ingesteld op 0, het is de functie van de gehele rest.
$ 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
Dat is niet hetzelfde als de wiskundige mod-functie. Dat los ik hieronder op.
-
Decimale rest.
Als het getaln
een langer decimaal getal is, en we wijzigen de schaal, krijgen we:$ 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 op dat hier de eerste 3 decimale cijfers zijn verwijderd en de rest die is opgegeven vanaf het vierde decimale cijfer.
$ bc <<<"n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d; print a," ",b,"\n"" .000000089 .000000089
Dat toont aan dat de rest wordt door die definitie veelzijdiger gemaakt.
Nu is het: de rest na de waarde van schaal.
-
Schaalwijziging De schaalwijziging is vereist omdat het getal
d
(deler) meer decimale cijfers kan hebben dann
. In dat geval er zijn meer decimalen nodig om een nauwkeuriger resultaat van de deling te krijgen:$ 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
En, als de schaal verandert 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
Zoals hierboven te zien is, verandert de schaalwaarde om een redelijk nauwkeurig resultaat te geven van de deling voor elke waarde van
n
,d
enscale
.
I” Ik neem aan dat door de vergelijking tussen de internalmod
en de %
operator is bewezen dat beide gelijkwaardig zijn.
-
Verwarring . Wees voorzichtig, want spelen met de waarde van
d
kan verwarrend worden:$ bc <<<"n=17.123456789; d=10; scale=3; a=n%d; print a," ",scale(a),"\n"" .003456789 9
En:
$ bc <<<"n=17.123456789; d=1000; scale=3; a=n%d; print a," ",scale(a),"\n"" .123456789 9
Dat is: de waarde van
d
(boven 1) zal het effect van de waarde van scale set wijzigen.
Waarschijnlijk moet u voor waarden van d
anders dan 1 gebruiken scale = 0 (tenzij u echt weet wat u doet).
-
Wiskundige mod .
Sinds we zijn door zo diep in de mod-functies te duiken, moeten we waarschijnlijk het echte effect van%
inbc
verduidelijken. De%
-operator in bc gebruikt een “truncating divisie”. Een die rondloopt in de richting van0
. Dat is belangrijk voor negatieve waarden van zoweln
en / ofd
:$ bc <<<"scale=0; n=13; d=7; n%d; " 6 $ bc <<<"scale=0; n=13; d=-7; n%d; " 6
Het teken van de rest volgt het teken van de
dividend
.$ bc <<<"scale=0; n=-13; d=7; n%d; " -6 $ bc <<<"scale=0; n=-13; d=-7; n%d; " -6
Hoewel een correcte math mod zou een altijd positieve rest moeten geven .
Om die (integer) mod-functie te krijgen, gebruik:
# 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 (dan) zal dit werken:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)" 6.123456789
[a]
expr% expr
Het resultaat van de uitdrukking is de “rest” en wordt als volgt berekend manier. Om a% b te berekenen, wordt eerst a / b berekend om cijfers te schalen.Dat resultaat wordt gebruikt om a- (a / b) * b te berekenen naar de schaal van het maximum van schaal + schaal (b) en schaal (a).
Als schaal is ingesteld op nul en beide uitdrukkingen zijn gehele getallen, deze uitdrukking is de gehele restfunctie.
Voor de bc
code die volgt op het punt waar deze voetnoot werd geïntroduceerd om correct te werken, definieer dan een alias als:
$ alias bc="bc -l "$HOME/.func.bc""
En maak een bestand met de naam $HOME/.func.bc
dat ( tenminste):
# 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)) }
Een mod-functie voor elk getal (geheel getal of niet) kan worden gedefinieerd als:
# 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) };
Deze definitie is volkomen geldig en correct volgens wiskundige regels, maar het kan behoorlijk verwarrend worden wanneer je het in echte gevallen probeert toe te passen door gewoon te zeggen.