Равно ли long x = 1/2 1 или 0, и почему?

если у меня есть что-то вроде:

long x = 1/2;

не следует ли округлять это значение до 1? Когда я печатаю это на экране, он говорит 0.


person user69514    schedule 02.02.2010    source источник
comment
Обратите внимание, что в вашем заголовке у вас была точка после «2», что означает константу с плавающей запятой и другой результат ... Я знаю, что вы имели в виду это как пунктуацию в предложении, но я нашел это сбивающим с толку.   -  person dmckee --- ex-moderator kitten    schedule 02.02.2010
comment
BigDecimal поддерживает пять режимов округления, почему округление должно быть единственным выбором?   -  person Peter Lawrey    schedule 03.02.2010
comment
Хорошо, я полагаю, вы читали документацию C / C ++ об операторе /, не так ли? ... Разве это не странный вопрос?   -  person botismarius    schedule 03.02.2010


Ответы (6)


Он выполняет целочисленное деление, которое обрезает все, что находится справа от десятичной точки.

person tvanfosson    schedule 02.02.2010
comment
Это утверждение не работает, если вы используете C и у вас отрицательные числа. Из C ++ я получил -5 / 2 = -2 (округление до нуля). Если вы отметите дополнение до двух, вы увидите, что это не простое усечение - это даст -5 / 2 = -3. Я подозреваю, что результат C ++ на самом деле определяется реализацией. - person Steve314; 03.02.2010
comment
@ Steve314: Ага. Стандарт C ++ дает вам это (a / b) * b + a % b == a и заверяет, что если a и b оба положительны, a / b и a % b будут неотрицательными. Если a и / или b отрицательны, знаки определяются реализацией (Стандарт, 5.6). У меня нет под рукой стандартных документов C или Java. - person David Thornley; 03.02.2010
comment
Он полностью определен в C (и я предполагаю, что это унаследовано C ++): When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded. (то есть, это является усечением, но усечение определяется относительно числового значения, а не базового представления). - person caf; 03.02.2010
comment
@caf - если то, что вы говорите, правда, это недавний стандарт, определяющий, что предыдущие стандарты оставили неопределенными. Тот факт, что он в настоящее время не определен в C ++, - это , потому что он не был определен в C в момент копирования стандарта. - person Steve314; 03.02.2010
comment
Это правда - это было определено реализацией в C89. - person caf; 03.02.2010
comment
@Steve: -5/2 = -2,5, что для целочисленного деления усекает 0,5, оставляя -2, что делает этот ответ полностью правильным. - person Lawrence Dol; 03.02.2010
comment
@Monkey - это не то, что происходит при работе в 2-х дополнениях. Текущий стандарт C, вероятно, делает базовое представление нерелевантным, но текущий стандарт C ++ и более старые стандарты C этого не делают. Когда вы выполняете усечение в двоичном коде с дополнением 2s, -5/2 = -3 (фактические двоичные шаги показаны в моем ответе). - person Steve314; 03.02.2010

Целочисленное деление уходит корнями в теорию чисел. Когда вы делаете 1/2, вы спрашиваете, сколько раз 2 равно 1? Ответ - никогда, поэтому уравнение принимает вид 0 * 2 + 1 = 1, где 0 - это частное (то, что вы получаете от 1/2), а 1 - остаток (то, что вы получаете от 1% 2).

Правильно отметить, что% не является истинным модулем в математическом смысле, а всегда является остатком от деления. Есть разница, когда вы имеете дело с отрицательными целыми числами.

Надеюсь, это поможет.

person Johann Oskarsson    schedule 02.02.2010
comment
По крайней мере, в C ++ это может быть настоящий модуль; это определяется реализацией. Признайтесь, не существует способа обработки целочисленного деления и остатков с отрицательными числами, который каждый найдет интуитивно понятным. - person David Thornley; 03.02.2010

Это выражение сначала объявляет о существовании long с именем x, а затем присваивает ему значение выражения в правой части. Выражение в правой части - 1/2, а поскольку 1 и 2 являются целыми числами, это интерпретируется как целочисленное деление. При целочисленном делении результатом всегда является целое число, поэтому что-то вроде 5/3 вернет 1, так как только одна тройка подходит к пятерке. Итак, с 1/2, сколько двоек может поместиться в 1? 0.

В некоторых языках это может привести к интересным результатам, если вы напишете что-то вроде double x = 1/2. В этом случае вы можете ожидать 0,5, но он часто сначала оценивает целочисленное значение справа, прежде чем присваивать и преобразовывать результат в двойной, давая значение 0,0

Важно отметить, что при выполнении такого преобразования типа результат никогда не округляется. Итак, если вы сделаете наоборот: long x = (long) (1.0 / 2.0); тогда, в то время как (1.0 / 2.0) будет оцениваться как 0.5, (длинное) приведение приведет к усечению этого значения до 0. Даже если у меня было long x = (long) (0.9), результат все равно будет 0. Он просто усекает после десятичной точки.

person Jacob Bellamy    schedule 02.02.2010

Он не может округляться, потому что он никогда не может быть округлен

Выражение "1/2" никогда не было 0,5 до присвоения long

Теперь long x = 1.0/2.0, потому что выражение справа перед assign допустимо для округления. Если вы не получите 0,499999999999997 ...

person gbn    schedule 02.02.2010
comment
Нет, присвоение числа с плавающей запятой целому числу по-прежнему приводит к усечению. Конечно, остальная часть вашей точки зрения о том, что целочисленное деление никогда не приводит к чему-либо с плавающей запятой, остается в силе. - person Chris Jester-Young; 02.02.2010
comment
@ Крис: да, я только что проверил точные правила. Это не то, на что я бы полагался изо дня в день. Спасибо - person gbn; 02.02.2010
comment
Я думаю, вы часто будете видеть такие вещи, как long x = 1.0 / 2.0 + 0.5. Я полагаю, даже это не поможет, если в результате вы получите 0,499999999999997 ... (что меня очень удивит в данном случае), но если это так, вероятно, ничего не помогает, кроме не округление чисел с плавающей запятой до целых чисел. - person UncleBens; 02.02.2010
comment
@UncleBens: Почему это вас удивит? - person jarnbjo; 03.02.2010
comment
@jambjo: Видя, что 1.0, 2.0 и 0.5 могут быть представлены точно (независимо от того, что называется типичный стандарт для плавающей запятой), и что при тестировании результат равен 1, как и ожидалось :) Я не говорю, что это сработает для всех входов, но если это не так, я не вижу способа, как можно было бы надежно округлить поплавки в первую очередь. (В принципе, если это имеет значение, вообще не следует использовать числа с плавающей запятой.) - person UncleBens; 03.02.2010
comment
@jambjo: Меня это удивило бы, потому что 0.5 точно представима в двоичной системе с плавающей запятой, и там нет ничего особенного. Что-то вроде (1.0 / 6.0) * 3.0 + 0.5 использует числа, которые нельзя точно представить в двоичном формате, и тогда я не удивлюсь неточным ответом. - person David Thornley; 03.02.2010
comment
Это напоминает мне аргумент, когда однажды кто-то пытался сказать мне, что что-то построенное неисправно, не сломано, потому что оно никогда не работало. Естественный язык не такой уж педантичный. Причастия прошедшего времени часто используются как прилагательные, иногда подразумевая прошлый переход в состояние, но так же часто описывая только текущее состояние. Для округления результата не требуется, чтобы машина выдала промежуточный неокругленный результат. - person Steve314; 03.02.2010

на этот вопрос уже был дан ответ на этом сайте, вы выполняете целочисленное деление, если хотите использовать 0,5:

double x = (double)1/2;

и вы получите значение 0.5.

person Jorgesys    schedule 27.12.2013

Существует множество различных соглашений об округлении, наиболее распространенными из которых являются округление в сторону + inf, округление в сторону -inf и округление в сторону нуля. Многие люди предполагают, что есть один правильный путь, но все они имеют разные представления о том, каким должен быть этот путь ;-)

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

С Visual C ++ я получаю 5/2 = 2 и -5/2 = -2, округляя до нуля.

Округление в C, C ++ и Java обычно называется «усечением», что означает отбрасывание ненужных битов. Но это может вводить в заблуждение. Используя 4-битное двоичное дополнение до 2, выполнение того, что подразумевает усечение, дает ...

 5/2 = 0101/0010 = 0010.1 --> 0010 =  2
-5/2 = 1011/0010 = 1101.1 --> 1101 = -3

Что округляется в сторону -infinity, что и делает Python (или, по крайней мере, то, что он делал в Python 2.5).

Усечение было бы правильным словом, если бы мы использовали представление величины знака, но дополнение до двоек было де-факто стандартом на протяжении десятилетий.

В C и C ++ я ожидаю, что, хотя это обычно называется усечением, на самом деле эта деталь не определена в стандартах и ​​оставлена ​​на усмотрение реализации - оправдание для разрешения компилятору использовать самый простой и самый быстрый метод для платформы (что инструкция по разделению процессоров естественно делает). Это проблема только в том случае, если у вас есть отрицательные числа - я еще не видел ни одного языка или реализации, которые дали бы 5/2 = 3.

Я не знаю, что говорит стандарт Java. В руководстве по Python указано деление по полу, что является общим термином для округления до бесконечности.

ИЗМЕНИТЬ

Дополнительное примечание - по определению, если a / b = c остаток d, то a = (b * c) + d. Чтобы это сохранилось, вы должны выбрать остаток в соответствии с вашим соглашением об округлении.

Люди склонны предполагать, что остатки и модули одинаковы, но значения со знаком WRT могут быть разными - в зависимости от правил округления. Значения по модулю по определению никогда не бывают отрицательными, но остатки могут быть отрицательными.

Я подозреваю, что правило Python округления к отрицательной бесконечности предназначено для гарантии того, что единственный оператор% действителен как в качестве остатка, так и по модулю. В C и C ++ то, что означает% (остаток или по модулю), определяется (да, как вы уже догадались) реализацией.

На самом деле в Ada есть два отдельных оператора - mod и rem. При делении требуется округление до нуля, поэтому mod и rem do дают разные результаты.

person Steve314    schedule 02.02.2010
comment
Стандарт C ++ требует, чтобы для положительных целых чисел a и b a % b было неотрицательным, поэтому 5 / 3 не могло быть 3, так как тогда 5 % 3 должно было бы быть -4. Он рекомендует округлять частное до нуля с отрицательными числами, но это определяется реализацией. - person David Thornley; 03.02.2010