-1
votes

Méthode sans succursale pour convertir FALSE / VRAI à -1 / + 1?

Qu'est-ce qu'un moyen sans succursale de faire le mappage suivant?

true -> +1
false -> -1


12 commentaires

"Mais je cherche une méthode pour éviter la branche" - pourquoi?


{vrai: 1} .get (foo, -1)


@Deceze, réponse intelligente! Mais une lisibilité affreuse (que je sais que vous savez). OP, la clarté est l'une des choses les plus importantes de la programmation. En Python, il est particulièrement important (cela fait partie d'être "Pythonic"). Si vous allez faire quelque chose d'inattendu ou difficile à lire, vous devriez avoir une bonne raison pour cela.


Python's Ternary 1 Si FOO SORE -1 n'est pas une "ramification si" en soi, c'est une expression. Dans quelle mesure cela violerait-il votre restriction arbitraire ...?


@Deceze Il est ramifiant dans le sens où il est compilé à ByTecode qui fait un saut conditionnel.


b - = (b - 1) * -1


@ Kaya3 Bien sûr, mais la plupart des solutions le feront quelque part. Il est donc vraiment important de clarifier ce que nous essayons vraiment de travailler ici.


Y compris faux dans le dictionnaire et juste faire une recherche normale du dictionnaire éviter cela, mais je ne comprends toujours pas pourquoi vous feriez cela


Je suis d'accord avec certains des autres commentateurs, c'est bizarre. Pouvez-vous clarifier des choses?


@Chris Je ne suis pas vraiment sûr de la raison pour laquelle il faut avoir une raison de la question. Curiosité intellectuelle? Performance? J'ai mentionné Python, mais il peut aussi bien être un langage de montage, auquel cas il y a des raisons évidentes d'éviter les branchements (c'est-à-dire une mauvaise répugnation de la branche).


@Deceze an si génère une condition Sauter dans le processeur opcode. La plupart des solutions font font cela, c'est pourquoi je pose cette question! Y a-t-il des moyens d'éviter une branche?


@puritiii, bien sûr la raison est importante. La curiosité intellectuelle et la performance conduisent à différentes réponses, par ex. Les solutions alternatives peuvent être intéressantes mais performer pire . Et futzez autour d'une sauvegarde des opcodes simples dans une langue comme Python est au mieux discutable. «J'ai mentionné Python, mais il peut aussi bien être un langage de montage», votre question est trop large. C'est très inhabituel pour une question valide d'avoir plusieurs balises de langue ici.


3 Réponses :


5
votes

Vous pouvez exploiter le fait que dans Python, le type bool est numérique: xxx

donc l'expression 2 * b - 1 donne les résultats souhaités: xxx

Cependant, il est discutable si cela est vraiment "sans succursale". Il sera compilé à Python Bytecode sans sauts conditionnels, mais l'interpréteur de bytecode fera certainement des sauts conditionnels afin de l'exécuter: à tout le moins, il doit vérifier quels opcodes à exécuter, quels types les opérandes de * et - ont, et ainsi de suite.


4 commentaires

Bonne réponse, mais encore une fois, je vais mettre en garde pour favoriser la lisibilité. J'aimerais savoir pourquoi si b alors 1 autre -1 est inacceptable car il est beaucoup plus clair.


Sur votre dernière phrase: il ne devrait y avoir aucune ramification à l'intérieur de la valeur true vs false: true et false vraiment do stocke les valeurs 1 et 0 en interne, le reste est donc juste arithmétique. Plus généralement, il y aura bien sûr beaucoup de branches car l'interprète interprète le bytecode, mais pas à la suite de la true / false distinction.


@Markdickinson Je voulais dire qu'il y a sûrement une ramification pour vérifier ce que l'opcode est, et / ou quels types d'opérandes sont, etc. Mais je vais éditer pour clarifier cela, merci.


@ kaya3: Et bien sûr je me trompe, car le code de multiplication entier presque certainement spécial zéro ... Spécifiquement, je pense que moyenne_value est une ramification dans cette ligne: Github.com/python/cpython/blob/...



3
votes

Peut-être que nous pouvons utiliser une liste d'une manière comme celle-ci: xxx pré>

mise à jour: et la manière opposée mentionnée dans les commentaires: p>

(-1, 1)[False]
# output -1

(-1, 1)[True]
# output 1


0 commentaires

5
votes

Voici une comparaison des solutions publiées dans les commentaires et les réponses jusqu'à présent.

Nous pouvons utiliser le DIS code> Module pour voir le partecode généré dans chaque cas; Cela confirme qu'il n'y a pas d'instructions de saut conditionnelles (dans le code Python lui-même, au moins), et nous indique également quelque chose sur les performances attendues, car le nombre d'opérations exécutées a un impact direct sur celui-ci (bien qu'ils ne soient pas parfaitement corrélés) . Le nombre d'appels de fonction est également pertinent pour la performance, car ceux-ci ont une surcharge particulièrement élevée. P>

@glannis tondper et @ kaya3: (- 1, 1) [B] code> ( 3 opcodes) h3> xxx pré>

@heapoverflow: - (- 1) ** b code> (4 opcodes) h3> xxx Pré>

@heapoverflow: B - (non b) code> (4 opcodes) h3> xxx pré>

@ kaya3: 2 * b - 1 code> (5 opcodes) h3> xxx pré>

@heapoverflow: ~ b ^ -b code> (5 opcodes) h3>
  1           0 LOAD_CONST               0 (2)
              3 LOAD_NAME                0 (int)
              6 LOAD_NAME                1 (b)
              9 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             12 BINARY_MULTIPLY
             13 LOAD_CONST               1 (1)
             16 BINARY_SUBTRACT


1 commentaires

@Heapoverflow J'ai supprimé les opcodes de retour_value de vos modifications pour la cohérence - ils sont un artefact de DIS et non pertinent pour la comparaison.