Comment déterminer si un nombre est positif ou négatif?

On m’a demandé lors d’une interview comment déterminer si un nombre est positif ou négatif. Les règles indexOf que nous ne devrions pas utiliser d’opérateurs conditionnels tels que < et > , des fonctions Java intégrées (comme la subssortingngsubssortingng , indexOf , startsWith et startsWith ), aucune expression rationnelle ou API.

J’ai fait quelques devoirs à ce sujet et le code est donné ci-dessous, mais cela ne fonctionne que pour le type entier. Mais ils m’ont demandé d’écrire un code générique qui fonctionne pour float , double et long .

  // This might not be better way!! SOP ((( number >> 31 ) & 1) == 1 ? "- ve number " : "+ve number ); 

des idées de votre côté?

Les nombres entiers sont faciles. Le double cas est plus délicat, jusqu’à ce que vous vous rappeliez des infinis.

Note: Si vous considérez les doubles constantes “partie de l’API”, vous pouvez les remplacer par des expressions débordantes telles que 1E308 * 2 .

 int sign(int i) { if (i == 0) return 0; if (i >> 31 != 0) return -1; return +1; } int sign(long i) { if (i == 0) return 0; if (i >> 63 != 0) return -1; return +1; } int sign(double f) { if (f != f) throw new IllegalArgumentException("NaN"); if (f == 0) return 0; f *= Double.POSITIVE_INFINITY; if (f == Double.POSITIVE_INFINITY) return +1; if (f == Double.NEGATIVE_INFINITY) return -1; //this should never be reached, but I've been wrong before... throw new IllegalArgumentException("Unfathomed double"); } 

Ce qui suit est une approche terrible qui vous ferait virer de n’importe quel travail …

Cela dépend de ce que vous obtenez une exception de dépassement de stack (ou ce que Java appelle) … Et cela ne fonctionnerait que pour des nombres positifs qui ne dévient pas de 0 comme des fous.

Les nombres négatifs sont corrects, puisque vous déborderiez à positif, et que vous obtenez ensuite une exception de dépassement de capacité de la stack [qui renverrait false, ou “oui, c’est négatif”]

 Boolean isPositive(T a) { if(a == 0) return true; else { try { return isPositive(a-1); }catch(StackOverflowException e) { return false; //It went way down there and eventually went kaboom } } } 

Cela ne fonctionnera que pour tout sauf [0..2]

 boolean isPositive = (n % (n - 1)) * n == n; 

Vous pouvez faire une meilleure solution comme celle-ci (fonctionne sauf pour [0..1])

 boolean isPositive = ((n % (n - 0.5)) * n) / 0.5 == n; 

Vous pouvez obtenir une meilleure précision en changeant la partie 0.5 avec quelque chose comme 2 ^ m (m entier):

 boolean isPositive = ((n % (n - 0.03125)) * n) / 0.03125 == n; 

Vous pouvez faire quelque chose comme ça:

 ((long) (num * 1E308 * 1E308) >> 63) == 0 ? "+ve" : "-ve" 

L’idée principale ici est que nous jetons un long et vérifions la valeur du bit le plus significatif. Comme un double / flottant compris entre -1 et 0 sera arrondi à zéro lorsqu’il est converti en long, nous multiplions par de grands doubles pour qu’un flottant / double négatif soit inférieur à -1. Deux multiplications sont nécessaires en raison de l’existence de sous – normales (il n’est pas vraiment nécessaire que ce soit si gros).

Et ça?

 return ((num + "").charAt(0) == '-'); 
 // Returns 0 if positive, nonzero if negative public long sign(long value) { return value & 0x8000000000000000L; } 

Appel comme:

 long val1 = ...; double val2 = ...; float val3 = ...; int val4 = ...; sign((long) valN); 

Passer de double / float / integer à long devrait préserver le signe, sinon la valeur réelle …

Vous dites

nous ne devrions pas utiliser des opérateurs conditionnels

Mais c’est une astuce, car == est aussi un opérateur conditionnel. Il y en a aussi un intégré ? : ? : , while , et for boucles. Donc, presque tout le monde n’a pas réussi à fournir une réponse répondant à toutes les exigences.

La seule façon de construire une solution sans opérateur conditionnel consiste à utiliser une table de consultation ou une des solutions d’autres personnes pouvant être réduites à 0/1 ou un caractère, avant qu’une condition ne soit remplie.

Voici les réponses que je pense pourraient fonctionner par rapport à une table de consultation:

  • Nabb
  • Steven Schlansker
  • Dennis Cheung
  • Gary Rowe

Cette solution utilise un module. Et oui, ça marche aussi pour 0.5 (les tests sont ci-dessous, dans la méthode principale).

 public class Num { public static int sign(long x) { if (x == 0L || x == 1L) return (int) x; return x == Long.MIN_VALUE || x % (x - 1L) == x ? -1 : 1; } public static int sign(double x) { if (x != x) throw new IllegalArgumentException("NaN"); if (x == 0.d || x == 1.d) return (int) x; if (x == Double.POSITIVE_INFINITY) return 1; if (x == Double.NEGATIVE_INFINITY) return -1; return x % (x - 1.d) == x ? -1 : 1; } public static int sign(int x) { return Num.sign((long)x); } public static int sign(float x) { return Num.sign((double)x); } public static void main(Ssortingng args[]) { System.out.println(Num.sign(Integer.MAX_VALUE)); // 1 System.out.println(Num.sign(1)); // 1 System.out.println(Num.sign(0)); // 0 System.out.println(Num.sign(-1)); // -1 System.out.println(Num.sign(Integer.MIN_VALUE)); // -1 System.out.println(Num.sign(Long.MAX_VALUE)); // 1 System.out.println(Num.sign(1L)); // 1 System.out.println(Num.sign(0L)); // 0 System.out.println(Num.sign(-1L)); // -1 System.out.println(Num.sign(Long.MIN_VALUE)); // -1 System.out.println(Num.sign(Double.POSITIVE_INFINITY)); // 1 System.out.println(Num.sign(Double.MAX_VALUE)); // 1 System.out.println(Num.sign(0.5d)); // 1 System.out.println(Num.sign(0.d)); // 0 System.out.println(Num.sign(-0.5d)); // -1 System.out.println(Num.sign(Double.MIN_VALUE)); // -1 System.out.println(Num.sign(Double.NEGATIVE_INFINITY)); // -1 System.out.println(Num.sign(Float.POSITIVE_INFINITY)); // 1 System.out.println(Num.sign(Float.MAX_VALUE)); // 1 System.out.println(Num.sign(0.5f)); // 1 System.out.println(Num.sign(0.f)); // 0 System.out.println(Num.sign(-0.5f)); // -1 System.out.println(Num.sign(Float.MIN_VALUE)); // -1 System.out.println(Num.sign(Float.NEGATIVE_INFINITY)); // -1 System.out.println(Num.sign(Float.NaN)); // Throws an exception } } 

Ce code couvre tous les cas et types:

 public static boolean isNegative(Number number) { return (Double.doubleToLongBits(number.doubleValue()) & Long.MIN_VALUE) == Long.MIN_VALUE; } 

Cette méthode accepte toutes les classes wrapper ( Integer , Long , Float et Double ) et grâce à la mise en boîte automatique des types numériques primitifs ( int , long , float et double ) et vérifie simplement le bit le plus élevé, qui dans tous les types est le bit de signe, est défini.

Il renvoie true lorsque vous transmettez l’un des éléments suivants:

  • tout Integer négatif / Integer
  • tout long / long négatif
  • tout float / float négatif
  • tout double négatif / Double
  • Double.NEGATIVE_INFINITY
  • Float.NEGATIVE_INFINITY

et false autrement.

Non testé, mais illustrant mon idée:

 boolean IsNegative(T v) { return (v & ((T)-1)); } 

Cela me semble arbitraire parce que je ne sais pas comment vous obtiendriez le nombre comme n’importe quel type, mais qu’en est-il de la vérification de Abs (nombre)! = Nombre? Peut-être que && nombre! = 0

Les entiers sont sortingviaux; c’est ce que vous savez déjà. Le problème majeur est de savoir comment gérer les valeurs à virgule flottante. À ce stade, vous devez en savoir un peu plus sur le fonctionnement des valeurs à virgule flottante.

La clé est Double.doubleToLongBits () , qui vous permet d’obtenir la représentation IEEE du numéro. (La méthode est vraiment directe sous le capot, avec un peu de magie pour gérer les valeurs NaN.) Une fois qu’un double a été converti en long, vous pouvez simplement utiliser 0x8000000000000000L comme masque pour sélectionner le bit de signe; si zéro, la valeur est positive et, le cas échéant, négative.

S’il s’agit d’une réponse valide

 boolean IsNegative(char[] v) throws NullPointerException, ArrayIndexOutOfBoundException { return v[0]=='-'; } 

une option de plus je pourrais penser

 private static boolean isPositive(Object numberObject) { Long number = Long.valueOf(numberObject.toSsortingng()); return Math.sqrt((number * number)) != number; } private static boolean isPositive(Object numberObject) { Long number = Long.valueOf(numberObject.toSsortingng()); long signedLeftShifteredNumber = number << 1; // Signed left shift long unsignedRightShifterNumber = signedLeftShifteredNumber >>> 1; // Unsigned right shift return unsignedRightShifterNumber == number; } 

Celui-ci est à peu près basé sur la réponse d’ItzWarty, mais il s’exécute en temps de connexion! Avertissement: Ne fonctionne que pour les entiers.

 Boolean isPositive(int a) { if(a == -1) return false; if(a == 0) return false; if(a == 1) return true; return isPositive(a/2); } 

Je pense qu’il existe une solution très simple:

 public boolean isPositive(int|float|double|long i){ return (((ii)==0)? true : false); } 

dis moi si je me trompe!

Essayez ceci sans le code: (x-SQRT(x^2))/(2*x)

Ecrivez-le en utilisant le conditionnel, puis jetez un coup d’œil au code d’assemblage généré.

Pourquoi ne pas obtenir la racine carrée du nombre? Si son négatif – java va lancer une erreur et nous allons le gérer.

  try { d = Math.sqrt(THE_NUMBER); } catch ( ArithmeticException e ) { console.putln("Number is negative."); } 

Je ne sais pas exactement comment Java coïncide les valeurs numériques, mais la réponse est assez simple, si on le place en pseudocode (je vous laisse les détails):

 sign(x) := (x == 0) ? 0 : (x/x) 

Si vous êtes autorisé à utiliser “==” comme cela semble être le cas, vous pouvez faire quelque chose comme cela en tirant parti du fait qu’une exception sera déclenchée si un index de tableau est hors limites. Le code est pour le double, mais vous pouvez convertir n’importe quel type numérique en double (ici, la perte éventuelle de précision ne serait pas importante du tout).

J’ai ajouté des commentaires pour expliquer le processus (apportez la valeur] -2.0; -1.0] union [1.0; 2.0 [) et un petit pilote de test également.

 class T { public static boolean positive(double f) { final boolean pos0[] = {true}; final boolean posn[] = {false, true}; if (f == 0.0) return true; while (true) { // If f is in ]-1.0; 1.0[, multiply it by 2 and restart. try { if (pos0[(int) f]) { f *= 2.0; continue; } } catch (Exception e) { } // If f is in ]-2.0; -1.0] U [1.0; 2.0[, return the proper answer. try { return posn[(int) ((f+1.5)/2)]; } catch (Exception e) { } // f is outside ]-2.0; 2.0[, divide by 2 and restart. f /= 2.0; } } static void check(double f) { System.out.println(f + " -> " + positive(f)); } public static void main(Ssortingng args[]) { for (double i = -10.0; i <= 10.0; i++) check(i); check(-1e24); check(-1e-24); check(1e-24); check(1e24); } 

La sortie est la suivante:

 -10.0 -> false -9.0 -> false -8.0 -> false -7.0 -> false -6.0 -> false -5.0 -> false -4.0 -> false -3.0 -> false -2.0 -> false -1.0 -> false 0.0 -> true 1.0 -> true 2.0 -> true 3.0 -> true 4.0 -> true 5.0 -> true 6.0 -> true 7.0 -> true 8.0 -> true 9.0 -> true 10.0 -> true -1.0E24 -> false -1.0E-24 -> false 1.0E-24 -> true 1.0E24 -> true 

Pas efficace, mais je suppose que ce n’est pas important ici (je suis aussi un peu rouillé avec Java, j’espère que c’est une syntaxe plus ou moins correcte.)

 boolean isPositive = false; int n = (int)(x * x); while (n-- != 0) { if ((int)(--x) == 0) { isPositive = true; break; } } 

Cela devrait fonctionner car x sera décrémenté au maximum x * x fois (toujours un nombre positif) et si x n’est jamais égal à 0, alors il doit avoir été négatif pour commencer. Si x , par contre, est égal à 0 à un moment donné, cela doit être correct.

Notez que isPositive serait false pour 0.

PS: Certes, cela ne fonctionnera pas avec des nombres très importants, car (int)(x * x) déborderait.

Eh bien, profitant du casting (puisque nous ne nous soucions pas de la valeur réelle), peut-être que les éléments suivants fonctionneraient. Gardez à l’esprit que les implémentations réelles ne violent pas les règles de l’API. Je l’ai modifié pour rendre les noms de méthode un peu plus évidents et à la lumière du commentaire de @chris sur le domaine à problèmes {-1, + 1}. Essentiellement, ce problème ne semble pas pouvoir être résolu sans recours aux méthodes API dans Float ou Double qui font référence à la structure de bits native des primitives float et double.

Comme tout le monde a dit: question d’interview stupide. Grr.

 public class SignDemo { public static boolean isNegative(byte x) { return (( x >> 7 ) & 1) == 1; } public static boolean isNegative(short x) { return (( x >> 15 ) & 1) == 1; } public static boolean isNegative(int x) { return (( x >> 31 ) & 1) == 1; } public static boolean isNegative(long x) { return (( x >> 63 ) & 1) == 1; } public static boolean isNegative(float x) { return isNegative((int)x); } public static boolean isNegative(double x) { return isNegative((long)x); } public static void main(Ssortingng[] args) { // byte System.out.printf("Byte %b%n",isNegative((byte)1)); System.out.printf("Byte %b%n",isNegative((byte)-1)); // short System.out.printf("Short %b%n",isNegative((short)1)); System.out.printf("Short %b%n",isNegative((short)-1)); // int System.out.printf("Int %b%n",isNegative(1)); System.out.printf("Int %b%n",isNegative(-1)); // long System.out.printf("Long %b%n",isNegative(1L)); System.out.printf("Long %b%n",isNegative(-1L)); // float System.out.printf("Float %b%n",isNegative(Float.MAX_VALUE)); System.out.printf("Float %b%n",isNegative(Float.NEGATIVE_INFINITY)); // double System.out.printf("Double %b%n",isNegative(Double.MAX_VALUE)); System.out.printf("Double %b%n",isNegative(Double.NEGATIVE_INFINITY)); // interesting cases // This will fail because we can't get to the float bits without an API and // casting will round to zero System.out.printf("{-1,1} (fail) %b%n",isNegative(-0.5f)); } } 

Cette solution ne nécessite aucun opérateur conditionnel, mais repose sur la capture de deux requêtes.

Une erreur de division équivaut à un nombre à l’origine “négatif”. Alternativement, le nombre finira par tomber de la planète et lancer une exception StackOverFlow si elle est positive.

 public static boolean isPositive( f) { int x; try { x = 1/((int)f + 1); return isPositive(x+1); } catch (StackOverFlow Error e) { return true; } catch (Zero Division Error e) { return false; } } 

Qu’en est-il de ce qui suit?

 T sign(T x) { if(x==0) return 0; return x/Math.abs(x); } 

Devrait fonctionner pour chaque type T …

Alternativement, on peut définir abs (x) comme Math.sqrt (x * x), et si cela sortingche aussi, implémentez votre propre fonction de racine carrée …

 if (((Double)calcYourDouble()).toSsortingng().contains("-")) doThis(); else doThat(); 

Génériques combinés avec double API. Je suppose que c’est un peu sortingcher, mais au moins nous devons écrire une seule méthode:

 static  boolean isNegative(T number) { return ((number.doubleValue() * Double.POSITIVE_INFINITY) == Double.NEGATIVE_INFINITY); } 

Deux solutions simples. Fonctionne également pour les infinis et les nombres -1 <= r <= 1 Renvoie "positif" pour NaN.

 Ssortingng positiveOrNegative(double number){ return (((int)(number/0.0))>>31 == 0)? "positive" : "negative"; } Ssortingng positiveOrNegative(double number){ return (number==0 || ((int)(number-1.0))>>31==0)? "positive" : "negative"; } 

C’est facile comme ça

 private static boolean isNeg(T l) { return (Math.abs(l-1)>Math.abs(l)); }