web-dev-qa-db-fra.com

Comprendre PHP & (esperluette, bit à bit et) opérateur

J'utilise souvent ($var & 1) dans mon code, qui renvoie vrai si $var est un nombre impair et faux s'il s'agit d'un nombre pair.

Mais que fait réellement "&"?

57
chipotle_warrior

& est binaire and. Si vous avez une valeur binaire et que vous and avec une autre valeur binaire, le résultat sera le and au niveau du bit des deux. Un exemple:

  01101010
& 01011001
= 01001000

Le bit le plus à droite est soit un 1 (et dans ce cas, le nombre est un nombre impair) ou c'est un 0, auquel cas le nombre est pair. Si vous & un nombre avec 1, vous ne regardez que le bit le moins significatif, et le if vérifie si le nombre est un 1 ou un 0. Comme d'autres l'ont mentionné, regardez les opérateurs au niveau du bit pour savoir comment ils fonctionnent.

59
Marius

Les deux opérations fondamentales pour les systèmes binaires sont OR et AND.

OU signifie "si A est activé ou B est activé". Un exemple réel serait deux commutateurs en parallèle. Si l'un ou l'autre laisse passer le courant, alors le courant passe.

ET signifie "si A et B sont allumés". L'exemple réel est deux commutateurs en série. Le courant ne passera que si les deux le permettent.

Dans un ordinateur, ce ne sont pas des commutateurs physiques mais des semi-conducteurs, et leurs fonctionnalités sont appelées portes logiques . Ils font le même genre de choses que les interrupteurs - réagissent au courant ou à l'absence de courant.

Lorsqu'il est appliqué à des entiers, chaque bit d'un numéro est combiné avec chaque bit de l'autre numéro. Donc, pour comprendre les opérateurs au niveau du bit OR et AND, vous devez convertir les nombres en binaire, puis faire l'opération OR ou AND sur chaque paire de bits correspondants) .

C'est pourquoi:

00011011 (odd number)
AND
00000001 (& 1)
== 
00000001 (results in 1)

Tandis que

00011010 (even number)
AND
00000001 (& 1)
==
00000000 (results in 0)

L'opération (& 1) compare donc le bit le plus à droite à 1 en utilisant la logique ET. Tous les autres bits sont effectivement ignorés car tout ET rien n'est rien. Un nombre pair en binaire est également un nombre pair en notation décimale (10 est un multiple de 2).

Les autres opérations fondamentales des systèmes binaires incluent NOT et XOR. NOT signifie "si A est désactivé" et est la seule forme de porte logique qui ne prend qu'un seul signal ou "paramètre" au lieu de deux. XOR signifie "si A ou B est activé, mais pas les deux". Et puis il y a NAND, NOR et NXOR, qui ne sont fondamentalement PAS combinés avec AND, OR et XOR, c'est-à-dire que NAND signifie 'si A et B sont pas tous les deux allumés'.

En programmation, l'opérateur

& means AND,
| means OR, 
~ means NOT, and
^ means XOR.

Les autres peuvent être constitués en les combinant, par exemple:

~ (a & b) is equivalent to a NAND operation

Note spécifique PHP

Les opérateurs au niveau du bit ne fonctionnent pas sur les valeurs à virgule flottante et dans PHP seront d'abord implicitement converties en entiers. Les nombres en dehors de la plage qui peuvent être exprimés sous forme d'entiers seront tronqués à zéro - cela Autrement dit, tous les nombres au-dessus de PHP_INT_MAX auront l'air "pairs" dans l'expression ($num & 1)). Si vous souhaitez prendre en charge des nombres en dehors de PHP_INT_MIN/PHP_INT_MAX, vous aurez besoin de fmod($num, 2). Si, cependant, vous êtes sur 64 bits PHP vos nombres entiers auront une plus grande précision que les flottants de toute façon.

26
thomasrutter

Il est également intéressant de connaître Bitwise et PHP:

/**
 * Regular
 */
echo (true && true); // 1
echo (true && false); // nothing

echo (true || false); // 1
echo (false || false); // nothing

echo (true xor false); // 1
echo (false xor false); // nothing

/**
 * Bitwise
 */
echo (true & true); // 1
echo (true & false); // 0

echo (true | false); // 1
echo (false | false); // 0

echo (true ^ false); // 1
echo (false ^ false); // 0
18
Ólafur Waage

En plus des autres réponses, il convient de noter que

if(func1() && func2())

Appellera uniquement func2() si func1() renvoie true ("évaluation paresseuse"), alors que

if(func1() & func2())

Appelera les deux fonctions indépendamment, mais les tables de vérité pour les deux seront les mêmes (en supposant qu'elles renvoient des booléens).


thomasrutter souligne (dans les commentaires ci-dessous) que vous ne devriez probablement pas faire ce dernier en pratique. (A & B) N'aura pas nécessairement la même véracité que (A && B), En particulier lorsque A et B sont des entiers. par exemple, si A = 1 et B = 2 (tous deux véridiques), A & B sera faux, tandis que A && B est véridique. En outre, un autre développeur peut penser qu'il s'agit d'une faute de frappe et la "corriger" sur deux esperluettes.

13
mpen

Je sais que votre question concerne la compréhension de l'opérateur au niveau du bit et la réponse acceptée l'explique bien. Mais pour l'exemple que vous donnez, je ne peux pas m'empêcher de vous recommander d'utiliser l'opérateur modulo à la place:

($var % 2) /* instead of */ ($var & 1)

Parce qu'il indique clairement que vous vérifiez que le nombre est impair (non divisible par deux) et qu'il est plus générique, vous pouvez donc utiliser ($ var% 3) de la même manière et en déduire comment cela fonctionne pour tout N.

12
Pat