Wenn die Skala nicht Null ist, geben Berechnungen mit%, z. B. 3% 2 und 46% 4, tendenziell 0 aus. Wie ist der Algorithmus mit einer anderen Skala als 0 ausgelegt?
Das Ergebnis des Ausdrucks ist der "Rest" und wird auf folgende Weise berechnet. Um a% b zu berechnen, wird zuerst a / b berechnet, um Ziffern zu skalieren. Dieses Ergebnis wird verwendet, um a - (a / b) * b auf die Skala des Maximums von Skala + Skala (b) und Skala (a) zu berechnen . Wenn die Skalierung auf Null gesetzt ist und beide Ausdrücke Ganzzahlen sind, ist dieser Ausdruck die Ganzzahl-Restfunktion.
EDIT:
Ich habe mir den Quellcode für GNU BC angesehen und festgestellt, dass der Mod-Operator den Divisionsoperator erweitert. Mit anderen Worten wird das Modulo als Nebenprodukt der Division berechnet. Es basiert auf einer ganzzahligen Division, um das Modulo zu berechnen. Wenn scaleeingestellt ist, findet jedoch keine Ganzzahldivision statt.
Versuchen Sie dies in BC:
bc
scale = 0
print 5/2
scale = 5
print 5/2
du solltest bekommen:
2 << Integer Division
2.50000 << NOT integer division!
Lassen Sie uns nun diese Zahlen wie BC einstecken. Das Handbuch sagt, dass es a- (a / b) * b verwendet, um zu berechnen. Lassen Sie uns unsere beiden Ergebnisse einfügen, das aus der Ganzzahldivision und das mit einer scaleanderen als 0.
a - ( a/b ) * b
5 - ( 2 ) * 2 = 1 << CORRECT!
5 - ( 2.5 ) * 2 = 0 << VERY WRONG!
Ohne ganzzahlige Division:
a - ( a/b ) * b == a - ( a ) == 0
Aus diesem Grund muss die Skalierung auf 0 gesetzt werden, damit das Modulo ordnungsgemäß funktioniert. Das Problem scheint sich aus dem Design von BC und dem Umgang mit Zahlen mit einer „Skala“ zu ergeben. Damit das Modulo richtig funktioniert, benötigen wir eine Ganzzahldivision .
Es gibt andere viel fortgeschrittenere Tools , die für diesen Zweck kostenlos und Open Source sind, und ich empfehle Ihnen, sie zu verwenden.
Ihre Skala ist 0, nicht "anders als Null". Bitte setzen Sie es zum Beispiel mit "scale = 10" und versuchen Sie es dann mit "3% 2".
2
Wenn dort "Skala" ohne Klammern steht, bezieht es sich auf die globale Variable "Skala".
Jweede
1
Ich bin mir nicht sicher, warum es sein muss, scale+scale(b)da das scalevon a / b im Allgemeinen Null sein sollte, damit es eine aussagekräftige Ausgabe liefert.
Jweede
1
Natürlich macht das Design BC effizienter für kleine "Debugging", obwohl nicht sicher, wie viel. Ihre anderen Tools, auf die verwiesen wird, können diese Art von Dingen möglicherweise besser handhaben, jedoch auf Kosten der Effizienz. +1
4
Ich habe es so gelöst:
ganze Zahl
definiere int (x) {oldscale = scale; Skala = 0; x = x / 1; scale = oldscale; return (x); }}
Modulo
definiere mod (x, y) {oldscale = scale; Skala = 1000; x = x - y * int (x / y); scale = oldscale; return (x); }}
Warum nicht define mod(x,y) { auto oldscale=scale; scale=0; x = x%y; scale=oldscale; return( x ); }?
SebMa
4
Die Antwort von user272970 ist großartig. Hier ist eine Optimierung:
define int(x) { auto oldscale; oldscale=scale; scale=0; x=x/1; scale=oldscale; return( x ); }
define fmod(x,y) { auto oldscale; oldscale=scale; scale=1000; x = x - y * int(x/y); scale=oldscale; return( x ); }
Dies (mit auto oldscale) macht oldscalelokal für die Funktion. Ohne diese Einstellung oldscalein int()von fmod () überschreibt die oldscalein gespeichert werden versucht fmod(), so dass scaleSatz bis 1000 statt , was Sie vor dem Aufruf hatten fmod().
Ich habe diese Funktionen hinzugefügt ~/.bcrcund die BC_ENV_ARGSUmgebungsvariable auf gesetzt ~/.bcrc. Dadurch werden diese Funktionen jedes Mal geladen, wenn Sie bc ausführen. Jetzt kann ich einfach fmod(x,y)jedes Mal ausgeführt werden, wenn ich in bc bin, ohne diese Funktionen jedes Mal manuell definieren zu müssen.
ps scalevon 1000 können in den meisten Fällen übertrieben sein
# 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) }
Angenommen, maxwurde definiert als:
define max(x,y){ if(x>y){return(x)};return(y) }
Wie ist diese lange Definition nützlich?
1. Ganzzahliger Rest .
Ich werde sowohl die internalmodFunktion als auch den %Operator verwenden, um zu zeigen, dass sie für einige der folgenden Operationen gleichwertig sind
Wenn die Zahlen ganzzahlig sind und die Skalierung auf 0 gesetzt ist, ist dies die ganzzahlige Restfunktion.
Das ist nicht dasselbe wie die Math Mod Funktion. Ich werde das unten lösen.
2. Dezimaler Rest.
Wenn die Zahl neine längere Dezimalzahl ist und wir die Skala ändern, erhalten wir:
$ 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
Beachten Sie, dass hier die ersten 3 Dezimalstellen entfernt wurden und der angegebene Rest von der vierten Dezimalstelle stammt.
$ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;print a," ",b,"\n"'
.000000089 .000000089
Dies zeigt, dass der Rest durch diese Definition vielseitiger wird.
3. Skalierungsänderung
Die Skalierungsänderung ist erforderlich, da die Zahl d(Divisor) möglicherweise mehr Dezimalstellen als enthält n. In diesem Fall sind mehr Dezimalstellen erforderlich, um ein genaueres Ergebnis der Division zu erhalten:
Das heißt: Der Wert von d(über 1) ändert den Effekt des Wertes der eingestellten Skala.
Wahrscheinlich sollten Sie für dandere Werte als 1 scale = 0 verwenden (es sei denn, Sie wissen wirklich, was Sie tun).
5. Math mod .
Da wir so tief in Mod-Funktionen eintauchen, sollten wir wahrscheinlich den wirklichen Effekt von %in klären bc. Der %Operator in bc verwendet eine "abschneidende Division". Eine, die auf sie zukommt 0. Das ist wichtig für negative Werte von beiden nund / oder d:
$ bc <<<'scale=0; n=13; d=7; n%d; '
6
$ bc <<<'scale=0; n=13; d=-7; n%d; '
6
Das Zeichen des Restes folgt dem Zeichen des dividend.
$ bc <<<'scale=0; n=-13; d=7; n%d; '
-6
$ bc <<<'scale=0; n=-13; d=-7; n%d; '
-6
Um diese (ganzzahlige) Mod-Funktion zu erhalten, verwenden Sie:
# 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)) }
Und das wird funktionieren:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
6.123456789
[ein]
Ausdruck% Ausdruck
Das Ergebnis des Ausdrucks ist der "Rest" und wird auf folgende Weise berechnet. Um a% b zu berechnen, wird zuerst a / b berechnet, um Ziffern zu skalieren. Dieses Ergebnis wird verwendet, um a- (a / b) * b auf die Skala des Maximums von Skala + Skala (b) und Skala (a) zu berechnen.
Wenn die Skalierung auf Null gesetzt ist und beide Ausdrücke Ganzzahlen sind, ist dieser Ausdruck die Ganzzahl-Restfunktion.
bcDefinieren Sie einen Alias für den Code, der dem Punkt folgt, an dem diese Fußnote eingeführt wurde, um ordnungsgemäß zu funktionieren:
$ alias bc='bc -l "$HOME/.func.bc"'
Und erstellen Sie eine Datei mit dem Namen $HOME/.func.bc, die (mindestens) enthält:
# 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)) }
Eine Mod-Funktion für eine beliebige Zahl (Ganzzahl oder nicht) kann definiert werden 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) };
Diese Definition ist nach mathematischen Regeln vollkommen gültig und korrekt. Sie kann jedoch ziemlich verwirrend werden, wenn Sie versuchen, sie in realen Fällen anzuwenden.
Wie andere Antworten gesagt haben, ist es das Ergebnis der Definition a%bals (a-(a/b)*b), bewertet zum aktuellen Zeitpunkt scale. Dies bedeutet, dass Sie es verwenden müssen, wenn Sie möchten, dass es als Ganzzahlmodul fungiert scale=0.
Ich bin jedoch nicht der Meinung, dass es "falsch" ist. Es ist ein potenziell nützliches Werkzeug, insbesondere zur Fehlerbewertung.
scale=5
1/3
> .33333
1%3
> .00001
Was verlieren wir, wenn wir 7/13als 4-stellige Dezimalstelle darstellen .5384?
scale=4
7/13
> .5384
7%13
> .0008
Anscheinend 0.0008/13.
Und schließlich kann es verwendet werden, um einen Teil einer Dezimalstelle zu extrahieren, da es nicht auf der Verwendung von Ganzzahlen besteht.
define mod(x,base){oldscale=scale; scale=0; result=x%base; scale=oldscale; return result }
Antworten:
In der Befehlsanleitung wird Folgendes darüber beschrieben, wie BC das Modulo berechnet:
EDIT: Ich habe mir den Quellcode für GNU BC angesehen und festgestellt, dass der Mod-Operator den Divisionsoperator erweitert. Mit anderen Worten wird das Modulo als Nebenprodukt der Division berechnet. Es basiert auf einer ganzzahligen Division, um das Modulo zu berechnen. Wenn
scale
eingestellt ist, findet jedoch keine Ganzzahldivision statt.Versuchen Sie dies in BC:
du solltest bekommen:
Lassen Sie uns nun diese Zahlen wie BC einstecken. Das Handbuch sagt, dass es a- (a / b) * b verwendet, um zu berechnen. Lassen Sie uns unsere beiden Ergebnisse einfügen, das aus der Ganzzahldivision und das mit einer
scale
anderen als 0.Ohne ganzzahlige Division:
Aus diesem Grund muss die Skalierung auf 0 gesetzt werden, damit das Modulo ordnungsgemäß funktioniert.
Das Problem scheint sich aus dem Design von BC und dem Umgang mit Zahlen mit einer „Skala“ zu ergeben. Damit das Modulo richtig funktioniert, benötigen wir eine Ganzzahldivision .
Es gibt andere viel fortgeschrittenere Tools , die für diesen Zweck kostenlos und Open Source sind, und ich empfehle Ihnen, sie zu verwenden.
quelle
scale+scale(b)
da dasscale
von a / b im Allgemeinen Null sein sollte, damit es eine aussagekräftige Ausgabe liefert.Ich habe es so gelöst:
ganze Zahl
definiere int (x) {oldscale = scale; Skala = 0; x = x / 1; scale = oldscale; return (x); }}
Modulo
definiere mod (x, y) {oldscale = scale; Skala = 1000; x = x - y * int (x / y); scale = oldscale; return (x); }}
HTH
quelle
define mod(x,y) { auto oldscale=scale; scale=0; x = x%y; scale=oldscale; return( x ); }
?Die Antwort von user272970 ist großartig. Hier ist eine Optimierung:
Dies (mit
auto oldscale
) machtoldscale
lokal für die Funktion. Ohne diese Einstellungoldscale
inint()
von fmod () überschreibt dieoldscale
in gespeichert werden versuchtfmod()
, so dassscale
Satz bis 1000 statt , was Sie vor dem Aufruf hattenfmod()
.Ich habe diese Funktionen hinzugefügt
~/.bcrc
und dieBC_ENV_ARGS
Umgebungsvariable auf gesetzt~/.bcrc
. Dadurch werden diese Funktionen jedes Mal geladen, wenn Sie bc ausführen. Jetzt kann ich einfachfmod(x,y)
jedes Mal ausgeführt werden, wenn ich in bc bin, ohne diese Funktionen jedes Mal manuell definieren zu müssen.ps
scale
von 1000 können in den meisten Fällen übertrieben seinquelle
Der
%
Bediener ist imbc
Handbuch klar definiert als [a] :Angenommen,
max
wurde definiert als:Wie ist diese lange Definition nützlich?
1. Ganzzahliger Rest .
Ich werde sowohl die
internalmod
Funktion als auch den%
Operator verwenden, um zu zeigen, dass sie für einige der folgenden Operationen gleichwertig sindWenn die Zahlen ganzzahlig sind und die Skalierung auf 0 gesetzt ist, ist dies die ganzzahlige Restfunktion.
Das ist nicht dasselbe wie die Math Mod Funktion. Ich werde das unten lösen.
2. Dezimaler Rest.
Wenn die Zahl
n
eine längere Dezimalzahl ist und wir die Skala ändern, erhalten wir:Beachten Sie, dass hier die ersten 3 Dezimalstellen entfernt wurden und der angegebene Rest von der vierten Dezimalstelle stammt.
Dies zeigt, dass der Rest durch diese Definition vielseitiger wird.
3. Skalierungsänderung Die Skalierungsänderung ist erforderlich, da die Zahl
d
(Divisor) möglicherweise mehr Dezimalstellen als enthältn
. In diesem Fall sind mehr Dezimalstellen erforderlich, um ein genaueres Ergebnis der Division zu erhalten:Und wenn sich der Maßstab ändert:
Wie oben zu sehen ist, dehnt sich der Skalenwert eine einigermaßen genaue Ergebnis der Division für jeden Wert von präsentieren
n
,d
undscale
.Ich gehe davon aus, dass sich durch den Vergleich zwischen dem
internalmod
und dem%
Bediener beide als gleichwertig erwiesen haben.4. Verwirrung . Seien Sie vorsichtig, da das Spielen mit dem Wert von
d
verwirrend werden kann:Und:
Das heißt: Der Wert von
d
(über 1) ändert den Effekt des Wertes der eingestellten Skala.Wahrscheinlich sollten Sie für
d
andere Werte als 1 scale = 0 verwenden (es sei denn, Sie wissen wirklich, was Sie tun).5. Math mod .
Da wir so tief in Mod-Funktionen eintauchen, sollten wir wahrscheinlich den wirklichen Effekt von
%
in klärenbc
. Der%
Operator in bc verwendet eine "abschneidende Division". Eine, die auf sie zukommt0
. Das ist wichtig für negative Werte von beidenn
und / oderd
:Das Zeichen des Restes folgt dem Zeichen des
dividend
.Während ein korrekter Mathe- Mod einen immer positiven Rest geben sollte .
Um diese (ganzzahlige) Mod-Funktion zu erhalten, verwenden Sie:
Und das wird funktionieren:
[ein]
bc
Definieren Sie einen Alias für den Code, der dem Punkt folgt, an dem diese Fußnote eingeführt wurde, um ordnungsgemäß zu funktionieren:Und erstellen Sie eine Datei mit dem Namen
$HOME/.func.bc
, die (mindestens) enthält:Eine Mod-Funktion für eine beliebige Zahl (Ganzzahl oder nicht) kann definiert werden als:
Diese Definition ist nach mathematischen Regeln vollkommen gültig und korrekt. Sie kann jedoch ziemlich verwirrend werden, wenn Sie versuchen, sie in realen Fällen anzuwenden.
quelle
Wie andere Antworten gesagt haben, ist es das Ergebnis der Definition
a%b
als(a-(a/b)*b)
, bewertet zum aktuellen Zeitpunktscale
. Dies bedeutet, dass Sie es verwenden müssen, wenn Sie möchten, dass es als Ganzzahlmodul fungiertscale=0
.Ich bin jedoch nicht der Meinung, dass es "falsch" ist. Es ist ein potenziell nützliches Werkzeug, insbesondere zur Fehlerbewertung.
Was verlieren wir, wenn wir
7/13
als 4-stellige Dezimalstelle darstellen.5384
?Anscheinend
0.0008/13
.Und schließlich kann es verwendet werden, um einen Teil einer Dezimalstelle zu extrahieren, da es nicht auf der Verwendung von Ganzzahlen besteht.
quelle