Подтвердить что ты не робот

Как определить, является ли число положительным или отрицательным?

Меня спросили в интервью, как определить, является ли число положительным или отрицательным. Правила заключаются в том, что мы не должны использовать условные операторы, такие как < и >, встроенные в java-функции (например, substring, indexOf, charAt и startsWith)), без регулярного выражения или API.

Я сделал некоторые домашние задания, и код приведен ниже, но он работает только для целочисленного типа. Но они попросили меня написать общий код, который работает для float, double и long.

 // This might not be better way!!

 S.O.P ((( number >> 31 ) & 1) == 1 ? "- ve number " : "+ve number );

любые идеи с вашей стороны?

4b9b3361

Ответ 1

Целые случаи легки. Двойной случай сложнее, пока вы не вспомните о бесконечности.

Примечание. Если вы рассматриваете двойные константы "часть api", вы можете заменить их переполняющими выражениями, например 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");
}

Ответ 2

Ниже приведен ужасный подход, который заставит вас уволить любую работу...

Это зависит от того, что вы получаете исключение [или что-то, что Java вызывает его]... И это будет работать только для положительных чисел, которые не отклоняются от 0 как сумасшедшие.

Отрицательные числа прекрасны, так как вы переполнили бы положительные значения, а затем получите исключение в конце [которое вернет false или "да, это отрицательно" ]

Boolean isPositive<T>(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
    }
  }
}

Ответ 3

Это будет работать только для всех, кроме [0..2]

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

Вы можете сделать лучшее решение, подобное этому (работает, кроме [0..1])

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

Вы можете получить лучшую точность, изменив 0,5 часть с чем-то вроде 2 ^ m (m integer):

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

Ответ 4

Вы можете сделать что-то вроде этого:

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

Основная идея здесь заключается в том, что мы отбрасываем до конца и проверяем значение самого значимого бита. Поскольку double/float между -1 и 0 будет округлено до нуля при нажатии на длинный, мы умножаем на большие двойники, чтобы отрицательный float/double был меньше -1. Требуется два умножения из-за существования субнормальных значений (на самом деле это не обязательно так важно).

Ответ 5

Как насчет этого?

return ((num + "").charAt(0) == '-');

Ответ 6

// Returns 0 if positive, nonzero if negative
public long sign(long value) {
    return value & 0x8000000000000000L;
}

Вызов:

long val1 = ...;
double val2 = ...;
float val3 = ...;
int val4 = ...;

sign((long) valN);

Кастинг из double/float/integer to long должен сохранять знак, если не фактическое значение...

Ответ 7

Вы говорите

мы не должны использовать условные операторы

Но это трюк, потому что == также является условным оператором. Существует также один встроенный в циклы ? :, while и for. Поэтому почти каждый не смог дать ответ, отвечающий всем требованиям.

Единственный способ построить решение без условного оператора - использовать таблицу поиска по сравнению с одним из нескольких других решений для людей, которые могут быть сведены к 0/1 или символу до того, как будет выполнено условие.

Вот ответы, которые, как я думаю, могут работать против таблицы поиска:

  • Nabb
  • Стивен Шланскер
  • Деннис Чунг
  • Гэри Роу

Ответ 8

Это решение использует модуль. И да, это также работает для 0.5 (тесты ниже, в основном методе).

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(String 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

    }
}

Ответ 9

Этот код охватывает все случаи и типы:

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

Этот метод принимает любой из классов-оболочек (Integer, Long, Float и Double) и благодаря автоматическому боксированию любого из примитивных числовых типов (int, Long, Float и Double) и просто проверяет его высокий бит, который во всех типах является знаковым битом.

Он возвращает true при передаче любого из следующих значений:

  • любой отрицательный int/Integer
  • любой отрицательный Long/Long
  • любой отрицательный Float/Float
  • любой отрицательный Double/Double
  • Double.NEGATIVE_INFINITY
  • Float.NEGATIVE_INFINITY

и false в противном случае.

Ответ 10

Неподтвержденный, но иллюстрирующий мою идею:

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

Ответ 11

Мне кажется произвольным, потому что я не знаю, как вы получили бы номер как любой тип, но как насчет проверки Abs (number)!= number? Может быть && число!= 0

Ответ 12

Целые тривиальны; это вы уже знаете. Глубокая проблема заключается в том, как иметь дело с значениями с плавающей запятой. В этот момент вы узнаете немного больше о том, как действительно работают значения с плавающей запятой.

Ключ Double.doubleToLongBits(), который позволяет вам получить представление IEEE этого числа. (Метод действительно прямой под капотом, с небольшим количеством магии для работы с значениями NaN.) Как только двойник был преобразован в длинный, вы можете просто использовать 0x8000000000000000L в качестве маски для выбора знакового бита; если ноль, значение положительное, а если оно отрицательное.

Ответ 13

еще один вариант, который я мог бы придумать

private static boolean isPositive(Object numberObject) {
Long number = Long.valueOf(numberObject.toString());
return Math.sqrt((number * number)) != number;
}

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

Ответ 14

Если это действительный ответ

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

Ответ 15

Этот пример основан на ответе ItzWarty, но он работает во время входа в систему! Caveat: работает только для целых чисел.

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

Ответ 16

Я думаю, что есть очень простое решение:

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

Скажи мне, если я ошибаюсь!

Ответ 17

Попробуйте это без кода: (x-SQRT(x^2))/(2*x)

Ответ 18

Запишите его с помощью условного выражения, затем посмотрите на сгенерированный код сборки.

Ответ 19

Почему бы не получить квадратный корень из числа? Если его отрицательный - java выдаст ошибку, и мы справимся с ней.

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

Ответ 20

Хорошо, пользуясь литьем (поскольку нам все равно, что такое реальная ценность), возможно, следующее будет работать. Имейте в виду, что фактические реализации не нарушают правила API. Я отредактировал это, чтобы сделать имена методов более очевидными и в свете комментария @chris о проблемном домене {-1, + 1}. По сути, эта проблема не представляется разрешимой без использования методов API в Float или Double, которые ссылаются на собственную битовую структуру float и двойных примитивов.

Как все говорили: глупый вопрос интервью. 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(String[] 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));

  }

}

Ответ 21

Я не знаю, как именно Java коэрцирует числовые значения, но ответ довольно прост, если положить в псевдокод (я оставляю детали вам):

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

Ответ 22

Если вам разрешено использовать "==", как кажется, вы можете сделать что-то подобное, воспользовавшись тем, что исключение будет поднято, если индекс массива выходит за пределы. Код для двойки, но вы можете использовать любой числовой тип для двойного (здесь конечная потеря точности вообще не будет важна).

Я добавил комментарии для объяснения процесса (добавьте значение в] -2.0; -1.0] union [1.0; 2.0 [) и небольшой тестовый драйвер.

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(String args[])
   {
       for (double i = -10.0; i <= 10.0; i++)
           check(i);
       check(-1e24);
       check(-1e-24);
       check(1e-24);
       check(1e24);
   }

Вывод:

-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

Ответ 23

Неэффективно, но я думаю, что здесь не важно: (Я тоже немного ржавый с Java, надеюсь, это более или менее правильный синтаксис.)

boolean isPositive = false;

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

Это должно работать, потому что x будет декрементировано не более x * x раз (всегда положительное число), а если x никогда не равно 0, то для начала оно должно быть отрицательным. Если x, с другой стороны, равно 0 в некоторой точке, оно должно быть поведенным.

Обратите внимание, что это приведет к тому, что isPositive будет false для 0.

P.S.: По общему признанию, это не будет работать с очень большими числами, так как (int)(x * x) будет переполняться.

Ответ 24

Это решение не использует условные операторы, но полагается на улавливание двух экскрементов.

Ошибка разделения означает, что число изначально было "отрицательным". В качестве альтернативы, число в конечном итоге упадет с планеты и выбросит исключение StackOverFlow, если оно будет положительным.

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;
           }


   }

Ответ 25

Как насчет следующего?

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

Должен работать для каждого типа T...

В качестве альтернативы можно определить abs (x) как Math.sqrt(x * x), и если это тоже обман, выполните свою собственную функцию квадратного корня...

Ответ 26

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

Ответ 27

Комбинированные дженерики с двойным API. Угадайте, что это немного обман, но по крайней мере нам нужно написать только один метод:

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

Ответ 28

Два простых решения. Работает также для бесконечностей и чисел -1 <= r <= 1 Вернет "положительный" для NaN.

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

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

Ответ 30

Легко это сделать, например

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