GNU BC: En quoi le «modulo» (%) avec une échelle autre que 0 est-il utile?

Ceci est une question à réponse automatique , la recherche quil est raisonnable de poser pour une question va dans la partie réponse, veuillez ne pas voter contre parce que vous pensez que je nai pas suffisamment recherché une réponse. Merci. En tout cas, il ny a pas de description (que je puisse trouver) de cette caractéristique de bc dans ce site.

Lorsque vous utilisez bc, le % est censé calculer le « reste », et oui, il fonctionne pour les nombres entiers et lorsque léchelle est égale à zéro :

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

Mais il ne parvient pas à donner le » reste entier « si léchelle nest pas zéro:

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

Pourquoi (ou comment) cette définition du % modulo est-elle utile?

Réponse

Lopérateur % est clairement défini dans le bc manuel comme [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) } 

En supposant que max a été défini comme:

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

En quoi cette longue définition est-elle utile?

  1. Integer restant .
    Je « montrerai à la fois le internalmod et lopérateur % permet de prouver quils sont équivalents pour certaines des opérations suivantes.

    Si les nombres sont des nombres entiers, et scale est mis à 0, cest la fonction de reste entier.

    $ 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 

Ce nest pas la même chose que la fonction math mod. Je « résoudrai cela ci-dessous.

  1. Reste décimal.
    Si le nombre n est un nombre décimal plus long et que nous modifions léchelle, nous obtenons:

    $ 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 

    Notez quici, les 3 premiers chiffres décimaux ont été supprimés et le reste donné provient du quatrième chiffre décimal.

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

    Cela montre que le reste est rendu plus polyvalent par cette définition.

Maintenant, cest: le reste après la valeur de léchelle.

  1. Changement déchelle Le changement déchelle est nécessaire car le nombre d (diviseur) peut avoir plus de chiffres décimaux que n. Dans ce cas, plus de décimales sont nécessaires pour avoir un résultat plus précis de la division:

    $ 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 

    Et, si léchelle change 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 

    Comme on peut le voir ci-dessus, la valeur déchelle change pour présenter un résultat raisonnablement précis de la division pour toute valeur de n, d et scale.

I » Supposons que la comparaison entre lopérateur internalmod et % sest avérée équivalente.

  1. Confusion . Attention car jouer avec la valeur de d peut devenir déroutant:

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

    Et:

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

    Autrement dit: la valeur de d (au-dessus de 1) modifiera leffet de la valeur de léchelle définie.

Probablement, pour des valeurs de d différentes de 1, vous devriez utiliser scale = 0 (à moins que vous ne sachiez vraiment ce que vous faites).

  1. Mod mathématique .
    Puisque nous sommes en approfondissant les fonctions des mods, nous devrions probablement clarifier leffet réel de % dans bc. Lopérateur % de bc utilise une « division tronquée ». Celui qui arrondit vers 0. Ceci est important pour les valeurs négatives de n et / ou d:

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

    Le signe du reste suit le signe de dividend.

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

    Bien quun math mod devrait donner à un reste toujours positif .

    Pour obtenir cette fonction de mod (entier), utilisez:

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

    Et (alors) cela fonctionnera:

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

[a]

expr% expr
Le résultat de lexpression est le « reste » et il est calculé dans ce qui suit chemin. Pour calculer a% b, dabord a / b est calculé pour mettre à léchelle les chiffres.Ce résultat est utilisé pour calculer a- (a / b) * b à léchelle du maximum déchelle + échelle (b) et échelle (a).
Si léchelle est définie sur zéro et que les deux expressions sont des entiers, cette expression est la fonction du reste de lentier.


Pour le code bc qui suit le point où cette note de bas de page a été introduit pour fonctionner correctement, définissez un alias comme:

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

Et créez un fichier nommé $HOME/.func.bc qui contient ( au moins):

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

Une fonction mod pour nimporte quel nombre (entier ou non) peut être définie comme:

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

Cette définition est parfaitement valide et correcte selon les règles mathématiques, cependant, cela peut devenir assez déroutant lorsquon essaie de lappliquer dans des cas réels, en disant simplement.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *