web-dev-qa-db-fra.com

Comment obtenir le signe d'un numéro?

Existe-t-il un moyen (simple) d'obtenir le "signe" d'un nombre (entier) dans PHP comparable à gmp_sign Documents :

  • -1 négatif
  • 0 zéro
  • 1 positif

Je me souviens qu'il existe une sorte de fonction de comparaison qui peut le faire, mais je ne suis pas en mesure de la trouver pour le moment.

J'ai rapidement compilé ceci ( Demo ) qui fait le travail, mais peut-être qu'il y a quelque chose de plus astucieux (comme un seul appel de fonction?), Je voudrais mapper le résultat sur un tableau:

$numbers = array(-100, 0, 100);

foreach($numbers as $number)
{
   echo $number, ': ', $number ? abs($number) / $number : 0, "\n";
}

(ce code pourrait probablement rencontrer des problèmes de précision en virgule flottante)

En relation: La requête # 19621 Math a besoin d'une fonction "sign ()"

33
hakre

Voici une doublure cool qui le fera pour vous de manière efficace et fiable:

function sign($n) {
    return ($n > 0) - ($n < 0);
}
52
Milosz

Dans PHP 7, vous devez utiliser opérateur de comparaison combiné (<=>):

$sign = $i <=> 0;
30
Peping

Une variante de ce qui précède dans ma question, j'ai testé et qui fonctionne aussi bien et n'a pas le problème de virgule flottante:

min(1, max(-1, $number))

Edit: Le code ci-dessus a une faille pour les nombres flottants (la question portait sur les nombres entiers) dans la plage supérieure à -1 et plus petit que 1 qui peut être corrigé avec le shorty suivant:

min(1, max(-1, $number == 0 ? 0 : $number * INF))

Celui-ci a toujours un défaut pour le flotteur NAN le faisant retourner -1 toujours. Ce n'est peut-être pas correct. Au lieu de cela, on peut vouloir retourner 0 ainsi que:

min(1, max(-1, (is_nan($number) or $number == 0) ? 0 : $number * INF))
17
hakre

Vous pouvez imbriquer des opérateurs ternaires:

echo $number, ': ',  ($number >= 0 ? ($number == 0 ? 0 : 1) : -1 )

Cela n'a aucun problème avec la précision en virgule flottante et évite une division en virgule flottante.

9
rocksportrocker

Quel est le problème avec ce formulaire?

if ( $num < 0 )
{
  //negative
}
else if ( $num == 0 )
{
  //zero
}
else
{
  //positive
}

ou ternaire:

$sign = $num < 0 ? -1 : ( $num > 0 ? 1 : 0 );

Pas sûr des performances de abs par rapport à la comparaison de valeurs, mais vous pouvez utiliser:

$sign = $num ? $num / abs($num) : 0;

et vous pouvez transformer n'importe lequel d'entre eux en fonction:

function valueSign($num)
{
  return $sign = $num < 0 ? -1 : ( $num > 0 ? 1 : 0 );
  //or
  return $sign = $num ? $num / abs($num) : 0;
}

Je suppose que vous pourriez parler de gmp_cmp , que vous pourriez appeler comme gmp_cmp( $num, 0 );

6
zzzzBov

Je pense que gmp_sign n'est pas très efficace car il attend un GMP ou une chaîne. ($ n? abs ($ n)/$ n: 0) est mathématiquement correct, mais la division coûte du temps. Les solutions min/max semblent devenir complexes inutiles pour les flotteurs.

($ n> 0) - ($ n <0) fait toujours 2 tests et une soustraction ($ n <0? -1: ($ n> 0? 1: 0) fait un ou deux tests et aucune arithmétique, il devrait mais je ne pense pas que la différence soit pertinente pour la plupart des cas d'utilisation.

4
Rolf

Je sais que c'est tard mais qu'en est-il simplement de diviser le nombre par les abs () de lui-même?

Quelque chose comme:

function sign($n) {
    return $n/(abs($n));
}

Mettez la gestion des erreurs que vous souhaitez pour div par zéro.

3
sansig

Utilisez strcmp Documents :

echo $number, ': ', strcmp($number, 0), "\n";
2
Toto

En voici une sans boucle:

function sign($number){
    echo $number, ': ', $number ? abs($number) / $number : 0, "\n";
}

$numbers = array(-100, 0, 100);

array_walk($numbers, 'sign');
1
Yeroon