Умножение двух целых чисел дает отрицательный результат

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

int progress = (byte_counter * 100) / size;
System.out.println("("+byte_counter+" * 100) = "+(byte_counter * 100)
  +" / "+size+" = "+progress);

byte-counter — это целое число (подсчитывается общее количество байтов, прочитанных из InputStream), а size — это длина загруженного файла в байтах.

Это отлично работает с небольшими загрузками. Но когда я добираюсь до файлов большего размера (40 МБ), он начинает делать забавные вещи. Результат расчета выглядит следующим образом:

[...]
(21473280 * 100) = 2147328000 / 47659008 = 45
(21474720 * 100) = 2147472000 / 47659008 = 45
(21476160 * 100) = -2147351296 / 47659008 = -45
(21477600 * 100) = -2147207296 / 47659008 = -45
[...]

Не знаю почему, но расчет получается отрицательным. Поскольку обычный Integer должен работать с числами до 231-1, это не должно быть корнем проблемы. Но что я упускаю?


person Lukas Knuth    schedule 18.05.2011    source источник
comment
Э-э, скорее, обычное целое число должно работать с числами до 2^31-1 или 2,147,483,647.   -  person StriplingWarrior    schedule 19.05.2011


Ответы (3)


См. http://en.wikipedia.org/wiki/Arithmetic_overflow.

Чтобы исправить в java, попробуйте вместо этого использовать long.

int progress = (int) ((byte_counter * 100L) / size);

или обратный порядок действий

int progress = (int) (((float) byte_counter) / size) * 100);
person Mike Samuel    schedule 18.05.2011
comment
Я так пробовал, проблема в том, что результат первого вычисления (byte_counter * 100) никогда не сохраняется ни в какой переменной (должен просто быть в памяти). Поэтому я не уверен, где указать используемый тип данных. - person Lukas Knuth; 19.05.2011
comment
@Lucas, обозначение 100L выше указывает значение long, равное 100. Это приведет к тому, что byte_counter будет повышено до long до того, как произойдет умножение. В общем, вы всегда можете заставить byte_counter повыситься до long, выполнив ((long) byte_counter). - person Mike Samuel; 19.05.2011

21476160 * 100 = 2 147 616 000 больше, чем 2 147 483 647, максимальное целое число.

Вы переполнены.

Используйте long для своих расчетов.

person Jonathon Faust    schedule 18.05.2011

Вы должны использовать длинное -- 2147760000 в двоичном формате равно 10000000 00000100 00110111 10000000, и поскольку старший бит равен 1, он интерпретируется как отрицательное число.

person Sai    schedule 18.05.2011