En complément de l'excellente réponse de FatalError, la ligne return f(b)^f(a-1);
pourrait être mieux expliqué. En bref, c'est parce que XOR a ces merveilleuses propriétés :
- C'est associatif - Placez les crochets où vous voulez
- C'est commutatif - cela signifie que vous pouvez déplacer les opérateurs (ils peuvent "faire la navette").
Voici les deux en action :
(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
Comme ça :
a ^ b = c
c ^ a = b
Ajouter et multiplier sont deux exemples d'autres opérateurs associatifs/commutatifs, mais ils ne s'inversent pas. Ok, alors, pourquoi ces propriétés sont-elles importantes ? Eh bien, une façon simple de procéder est de l'étendre à ce qu'il est réellement, et vous pourrez alors voir ces propriétés à l'œuvre.
Tout d'abord, définissons ce que nous voulons et appelons-le n :
n = (a ^ a+1 ^ a+2 .. ^ b)
Si cela peut vous aider, pensez à XOR (^) comme si c'était une addition.
Définissons également la fonction :
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b
est supérieure à a
Ainsi, en ajoutant quelques parenthèses supplémentaires (ce qui est possible car il s'agit d'une association), nous pouvons également dire ceci :
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
Ce qui se simplifie à :
f(b) = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)
f(b) = f(a-1) ^ n
Ensuite, nous utilisons cette propriété d'inversion et la commutivité pour nous donner la ligne magique :
n = f(b) ^ f(a-1)
Si vous aviez pensé à XOR comme à une addition, vous auriez ajouté une soustraction ici. XOR est à XOR ce que l'addition est à la soustraction !
Comment je fais pour trouver ça moi-même ?
Rappelez-vous les propriétés des opérateurs logiques. Travaillez avec eux presque comme une addition ou une multiplication si cela vous aide. Il semble inhabituel que and (&), xor (^) et or (|) soient associatifs, mais ils le sont !
Exécutez d'abord l'implémentation naïve, recherchez des modèles dans la sortie, puis commencez à trouver des règles qui confirment que le modèle est vrai. Simplifiez encore plus votre implémentation et répétez. Il s'agit probablement de la voie choisie par le créateur original, ce qui est mis en évidence par le fait qu'elle n'est pas complètement optimale (c'est-à-dire qu'il faut utiliser une instruction switch plutôt qu'un tableau).