Ajoutant à l'excellente réponse de FatalError, la ligne return f(b)^f(a-1);
pourrait être mieux expliquée. En bref, c'est parce que XOR a ces merveilleuses propriétés:
- C'est associatif - Placez des crochets où vous le souhaitez
- 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, un moyen simple est de l'étendre à ce qu'il est vraiment, et vous pourrez ensuite 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 aide, pensez à XOR (^) comme s'il s'agissait d'un ajout.
Définissons également la fonction:
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b
est supérieur à a
, donc simplement en ajoutant en toute sécurité quelques crochets supplémentaires (ce que nous pouvons car c'est associatif), nous pouvons également dire ceci:
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
Ce qui se simplifie en:
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 cette commutivité pour nous donner la ligne magique:
n = f(b) ^ f(a-1)
Si vous avez pensé à XOR comme un ajout, vous y auriez ajouté une soustraction. XOR est à XOR ce que ajouter c'est soustraire!
Comment puis-je trouver cela moi-même?
Souvenez-vous des propriétés des opérateurs logiques. Travaillez avec eux presque comme un ajout ou multipliez si cela aide. Il semble inhabituel que et (&), xor (^) et ou (|) 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 mise en œuvre et recommencez. C'est probablement la route empruntée par le créateur original, mise en évidence par le fait qu'elle n'est pas complètement optimale (c'est-à-dire utiliser une instruction switch plutôt qu'un tableau).