J'ai écrit un programme pour la relation de récurrence suivante:
An = 5An-1 - 2An-2 - An-3 + An-4
La sortie devrait être le module de réponse 10 ^ 9 + 7 .. J'ai écrit une approche par force brute pour celle-ci comme suit ...
long long int t1=5, t2=9, t3=11, t4=13, sum;
while(i--)
{
sum=((5*t4) - 2*t3 - t2 +t1)%MOD;
t1=t2;
t2=t3;
t3=t4;
t4=sum;
}
printf("%lld\n", sum);
où MOD= 10^9 +7
Tout semble vrai .. mais j'obtiens une réponse négative pour certaines valeurs .. et à cause de ce problème, je n'arrive pas à trouver la bonne solution ... Aidez Plz sur le bon endroit pour garder le Modulus
Le fait est que l'opérateur% n'est pas "l'opérateur modulo" mais l'opérateur "division reste" avec l'égalité suivante
(a/b)*b + a%b == a (for b!=0)
Donc, si dans le cas où votre division entière arrondit vers zéro (ce qui est obligatoire depuis C99 et C++ 11, je pense), -5/4 sera -1 et nous avons
(-5/4)*4 + -5%4 == -5
-1 *4 -1 == -5
Afin d'obtenir un résultat positif (pour l'opération modulo), vous devez ajouter le diviseur au cas où le reste était négatif ou faire quelque chose comme ceci:
long mod(long a, long b)
{ return (a%b+b)%b; }
En utilisant %
une deuxième fois dans les réponses de @ sellibitze et @ liquidblueocean ne sera probablement pas aussi lente que %
a tendance à être générale, car elle se résume à une soustraction de b
ou à aucune. En fait, permettez-moi de vérifier que ...
int main(int argc, char **argv) {
int a = argc; //Various tricks to prevent the
int b = 7; //compiler from optimising things out.
int c[10]; //Using g++ 4.8.1
for (int i = 0; i < 1000111000; ++i)
c[a % b] = 3;
//c[a < b ? a : a-b] = 3;
return a;
}
Vous pouvez également commenter la ligne avec %
ou l'autre ligne, on obtient:
Avec %
: 14 secondes
Avec ?
: 7 secondes
Alors %
n'est pas aussi optimisé que je ne le pensais. Probablement parce que cette optimisation ajouterait des frais généraux.
Par conséquent, il vaut mieux ne pas utiliser %
deux fois, pour des raisons de performances.
Au lieu de cela, comme cette réponse suggère et explique, faites ceci:
int mod(int k, int n) {
return ((k %= n) < 0) ? k+n : k;
}
Cela prend n peu plus de travail si vous voulez qu'il fonctionne correctement pour les négatifs n
aussi , mais ce n'est presque jamais nécessaire.
Remplacez simplement %
par une fonction qui gère les valeurs négatives:
long long int mod(long long int a, long long int b) {
long long int ret = a % b;
if (ret < 0)
ret += b;
return ret;
}
EDIT: a changé le type de données en long long int
.
Toutes les réponses actuellement ici qui ont un ajout ponctuel dans leur formule sont fausses lorsque abs (a)> b. Utilisez ceci ou similaire:
int modulo (int a, int b) { return a >= 0 ? a % b : ( b - abs ( a%b ) ) % b; }
Comme d'autres l'ont dit %
n'est qu'un opérateur restant plutôt que mod
. Cependant, l'opération mod/reste se distribue correctement via des relations de récurrence comme celle-ci, donc si vous ajustez simplement votre solution finale pour qu'elle soit positive, comme ceci,
if (sum < 0) { sum = sum + MOD; }
alors vous devriez obtenir la bonne réponse. L'avantage de procéder de cette façon est que vous introduisez un appel de fonction et/ou une branche de moins par itération de boucle. (Ce qui peut ou non avoir de l'importance selon le niveau d'intelligence de votre compilateur).