как Java определяет результат арифметического выражения - PullRequest
2 голосов
/ 13 октября 2019

Я пишу парсер для Java, однако, я немного растерялся, когда дело доходит до операций над примитивными типами.

Например, у меня есть такие выражения:

int i;
long l;
float f;
short s;
byte b;
//this is being cast from a float to an int? should this be a cast from byte?
int var1 = (int) (l * i * f * s * b);
//this is being cast from a float to an int? should this be a cast from long?
int var2 = (int) (l * (i * f * s * b));
//again casting from float to int? should this be a cast from short?
int var3 = (int) ((f) * (l) * (s));
//this seems to be a float but i expected this to be a long
int var4 = (int) ((f) * (l));

Я верилчто последней выполняемой операцией будет результирующий тип, однако, похоже, что это не тот случай, как в приведенных выше примерах. (Я не перечислял никаких операций с двойными числами, однако, похоже, что двойное имеет приоритет, как это делает float.)

Мое другое мнение состоит в том, что, поскольку он должен выполнять арифметику с плавающей запятой, он преобразует его всамый большой (32/64) битовый тип, так что никакая информация не теряется, если только нет определенного приведения, скрывающего тот факт, что было с плавающей запятой / double, например, следующее выражение оценивается как long.

int var1 = (l * i * (int) d * s * b);

Это мышление не соответствует действительности, однако, если в одном и том же выражении есть long / float, есть вероятность, что вы потеряете информацию, если значение long слишком велико, чтобы вписаться вплавать.

1 Ответ

3 голосов
/ 13 октября 2019

Две наиболее важные детали, которые вы можете найти в спецификации языка :

  • Умножение (и сложение, вычитание, деление и т. Д.) - это левоассоциативные . Итак:

    l * i * f * s * b
    

    оценивается как

    (((l * i) * f) * s) * b
    
  • Операнды умножения (и сложения, вычитания, деления и т. Д.) Подвергаются двоичное числовое продвижение . В широком смысле это означает, что операнды расширены, чтобы быть совместимыми друг с другом.

    Точнее:

    • Если один операнд является двойным, другой расширяется до двойного
    • В противном случае, если один операнд является плавающим, другой расширяется до плавающего
    • В противном случае, если один операнд длинный, другой расширяется до длинного
    • В противном случае оба операнда расширяютсяв int

    Последний пункт говорит вам, что даже при умножении одинаковых типов, скажем, коротких и коротких, операнды все еще расширяются до int

С этимидве точки:

  • l * i является длинной
  • (l * i) * f является плавающей точкой
  • ((l * i) * f) * s является плавающей точкой
  • (((l * i) * f) * s) * b это число с плавающей точкой.

Итак, вы преобразуетесь с числа с плавающей точкой на int.

...