2014-07-31 3 views
1

Хорошо. Я думаю, что это невозможно. Если вы считаете то же самое, вам не нужно публиковать ответ. Я прочитал несколько строк из Chapter 5. Conversions and Promotions, и кажется, что в главе 5 нет упоминаний об отключении Conversions and Promotions в Java.Как отключить конверсии и рекламные акции на Java?

Вот моя мотивация:

long uADD(long a, long b) { 
    try { 
     long c; 
     c = 0; 
     boolean carry; //carry flag; true: need to carry; false: no need to carry 
     carry = false; 
     for (int i = 0; i < 64; ++i) { //i loops from 0 to 63, 
      if (((((a >>> i) & 1)^((b >>> i)) & 1) != 0)^carry) { //calculate the ith digit of the sum 
       c += (1 << i); 
      } 
      if (((((a >>> i) & 1) & ((b >>> i) & 1)) != 0) || (carry && ((((a >>> i) & 1)^((b >>> i) & 1)) != 0))) { 
       carry = true; //calculate the carry flag which will be used for calculation of the (i+1)th digit 
      } else { 
       carry = false; 
      } 
     } 
     if (carry) { //check if there is a last carry flag 
      throw new ArithmeticException(); //throw arithmetic exception if true 
     } 
     return c; 
    } catch (ArithmeticException arithmExcep) { 
     throw new ArithmeticException("Unsigned Long integer Overflow during Addition"); 
    } 
} 

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

Во-первых, существует петля for, где i петли от 0 до 63.

Тогда первые if заявление действует как выходная сумму полного сумматора, он использует i ю цифру a и что из b и carry флага для расчета i + 1-й разряда (true или false). (Обратите внимание, что i = 0 соответствует цифре единиц.) Если true, он добавляет 1 << i в c, где c изначально 0.

После этого второй if заявление действует как выходной флаг переноса полного сумматора, он использует снова i ю цифру a и что из b и carry флага для расчета carry флага i + 1 го разряда. Если true, установите новый флаг carry на номер true, если false, установите новый флаг carryfalse.

Наконец, после выхода из петли for проверьте, соответствует ли флаг carrytrue. Если true, бросьте арифметическое исключение.

Однако приведенный выше код не работает. После отладки, оказывается, проблема возникает при

c += (1 << i); 

Правильный код должен быть:

c += (1L << i); 

потому, что Java будет автоматически продвигать целое 1 << i к Лонгу и добавить его в c, не проявляя никакого предупреждения мне ,

У меня есть несколько вопросов относительно этого.

  1. Можно ли отключить автоматическое продвижение одного типа данных в другой
  2. Как часто вызывает автоматическое продвижение проблемы для вас?
  3. Можно ли настроить среду IDE так, чтобы она показывала мне предупреждение при автоматическом продвижении по службе? (Я использую NetBeans IDE 7.3.1 на данный момент.)

Извините за множество вопросов и трудночитаемый код. Я буду изучать CS в сентябре, поэтому я пытаюсь написать код на Java, чтобы ознакомиться с Java.

+3

глава 5 ????/ –

+0

извините, забыть URL –

+1

Возможно, 'FindBugs' будет отмечать этот оператор. –

ответ

2

Можно ли отключить автоматическое продвижение одного типа данных в другой

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

Как часто автоматическое продвижение по службе вызывает у вас проблемы?

Возможно, раз в год (и я код на Java для жизни)?

Можно ли настроить среду IDE так, чтобы она показывала мне предупреждение при автоматическом продвижении по службе? (В настоящее время я использую IDE 7.3.1 на NetBeans.)

Следует отметить, что такое предупреждение не будет выявлять все случаи, когда требуется явное продвижение. Например, рассмотрим:

boolean isNearOrigin(int x, int y, int r) { 
    return x * x + y + y < r * r; 
} 

Несмотря на то, что нет автоматического продвижения, то умножений может вытечь, что может сделать метод возвращать неверные результаты, и один, вероятно, следует написать

return (long) x * x + (long) y + y < (long) r * r; 

вместо этого.

Также стоит отметить, что ваше предлагаемое предупреждение также появится для правильного кода. Например:

int x = ...; 
foo(x); 

предупредит об автоматическом продвижении, если foo объявлена ​​с типом параметра long, несмотря на то, что продвижение по службе не может иметь каких-либо побочных эффектов. Поскольку такие невинные ситуации довольно часты, ваше предупреждение, вероятно, будет настолько раздражать, что все его отключат. Поэтому я очень удивился тому, что любой компилятор Java выпустил такое предупреждение.

В общем, компилятор не может обнаружить, что операция будет переполняться, и даже поиск вероятных кандидатов для переполнения является сложным. Учитывая редкость проблем, связанных с переполнением, такое несовершенное обнаружение кажется сомнительным преимуществом, поэтому, вероятно, поэтому компиляторы Java и IDE не реализуют его. Поэтому программист должен нести ответственность за каждую арифметическую операцию, что значение, заданное типами операндов, является подходящим. Сюда входит указание подходящих типов суффиксов для любых числовых литералов, используемых в качестве операндов.

PS: Хотя я впечатлен тем, что вы получили ваш ряби нести сумматор работает, я думаю, что ваш метод uAdd может быть легко реализовано следующим образом:

long uAdd(long a, long b) { 
    long sum = a + b; 
    if (uLess(sum, a)) { 
     throw new ArithmeticException("Overflow"); 
    } else { 
     return sum; 
    } 
} 

/** @return whether a < b, treating both a and b as unsigned longs */ 
boolean uLess(long a, long b) { 
    long signBit = 1L << -1; 
    return (signBit^a) < (signBit^b); 
} 

Чтобы понять, почему это правильно, пусть < Обозначим меньше, чем отношение для подписанной интерпретации (что эквивалентно оператору Java), а «означает меньшее отношение для неподписанных значений. Пусть a и b - любая битовая диаграмма, из которой a 'и b' получаются переворачиванием знакового бита.По определению целых чисел, мы тогда имеем:

  • Если знак (а) = знак (б), имеем (а «Ь) = (а««Ъ„) = (а“< Ь»)
  • Если знак (а) ≠ знак (б), имеем (а «Ь) = (Ь '« а ') = (а' < Ь')

Поэтому (а «Ь) = (a '< b').

+0

Спасибо за подробное объяснение и альтернативный способ его выполнения. Поэтому кажется, что этот тип проблемы очень редок даже для коммерческого программиста. Я должен стараться быть осторожным, когда делаю побитую операцию. Наконец, 'boolean uLess (long a, long b) { long signBit = 1L << -1; return (signBit^a) <(signBit^b); } ', где происходит вся магия. Кажется, мне нужно время, чтобы понять это. –

+0

Я добавил эскиз доказательства. – meriton

+0

Большое спасибо за дальнейшее объяснение –

 Смежные вопросы

  • Нет связанных вопросов^_^