2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 
 Помогите разобраться с типами данных
Сообщение05.11.2011, 21:19 
Вечер добрый всем!

У меня есть такой код:

int main()
{
int N;
scanf("%d", &N);

long int p = 1+ N*(N+1)/2;

printf("%lu", p);
}

Максимальное N = 65535, т.е. в int влезает. При таком N получаем N*(N+1) = 4294901760, тогда в p ответ влезет (ведь long int = 2^(32)-1).

Но при вводе N = 65535 я получаю неверный ответ. В чем здесь может быть ошибка?

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 21:42 
Аватара пользователя
http://citforum.ru/programming/cpp_march/cpp_061.shtml

Цитата:
В арифметическом выражении тип результата выражения определяется самым "широким" типом среди всех образующих выражение операндов. Этот тип называют результирующим типом выражения. К этому типу преобразуются все остальные операнды.

Следуя этому правилу при вычисления выражения
long int p = 1+ N*(N+1)/2;

N+1 усечёться до типа N=int
(N+1)/2 тоже усечётся до типа int

Чтобы этого не происходила надо явно указать приведение типа.
long int p = 1+ N*(long int(N)+1)/2;

PS. Я бы перепроверил citforum.ru по стандарту. И справке на компилятор
PPS. В паскале другие правила.

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 21:55 
Не, так не работает: long int p = 1+ N*(long int(N)+1)/2;

И если выводить N*(N+1), то ответ верный, а как только пишу N*(N+1)/2, то уже выводит не то, что надо.

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 22:14 
Аватара пользователя
_Student
Кстати о птичках. Вы не указали какой ответ правильный, а какой нет. То есть какой хотите, что получаете?

А да еще надеюсь приоритет операций вы правильно учли?

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 22:19 
Считаю в СКА Maple 1+ N*(N+1)/2 при N = 65535 и получаю такой вот ответ: 2147450881. Он мне и нужен. А программа выводит 4294934529.

Приоритет операций? В смысле, что сначала сложение в скобках, далее умножение, потом деление, и наконец сложение, Вы это имеете ввиду?

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 22:49 
Аватара пользователя
Вот смотри.
http://en.cppreference.com/w/cpp/langua ... precedence
http://ru.wikipedia.org/wiki/Си_(язык_программирования)

Приоритеты такие что вначале выполняется "*" потом "/". Как в Maple не знаю.
Так вот вот тут у вас ошибка в рассуждениях
Цитата:
ведь long int = 2^(32)-1

long int имеет максимум 2^(31)-1. Число то знаковое, поэтому при перемножение мы имеем переполнение что выражается как -65536
Это не было бы страшным если бы не деление. Деление знаковое отличается от без знакового.
-65536 поделим на 2; сохраняет старший знаковый разряд
откуда получим -32768
А после прибавляется 1 и ответ выводиться.

Чтобы переполнения не было используй беззаконный тип.
unsigned long p = 1+ N*((unsigned long)N+1)/2;

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 22:54 
_Student, N*(N+1) уже переполнит тип int и результат умножения будет трактоваться как -65536. Почему у вас в результате получилось большое положительное число - отдельная история.
Использование long, скорее всего, ничего не изменит, т.к. на многих 32-битных системах тип long имеет размер 32-бита.
Если максимум N именно 65535, то в принципе хватит 32-битного unsigned: 1+unsigned(N)*(N+1)/2.
Иначе придётся использовать 64-битные типы - (long long int) или (int64_t) в зависимости от компилятора.

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 23:09 
"Почему у вас в результате получилось большое положительное число - отдельная история."
А почему оно получается? Причем верное получается, если просто вывести N*(N+1).

Вот так работает:

int main()
{
unsigned int N;
scanf("%d", &N);

unsigned long p = 1+(unsigned)(N*(N+1)/2);

printf("%lu", p);
}

Большое спасибо за помощь!

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 23:23 
_Student в сообщении #499928 писал(а):
"Почему у вас в результате получилось большое положительное число - отдельная история."
А почему оно получается? Причем верное получается, если просто вывести N*(N+1).
Потому что при выводе у вас unsigned формат, т.е. отрицательное число преобразуется в большое unsigned.

_Student в сообщении #499928 писал(а):
Вот так работает:

int main()
{
unsigned int N;
scanf("%d", &N);

unsigned long p = 1+(unsigned)(N*(N+1)/2);

printf("%lu", p);
}

Большое спасибо за помощь!
Вы точно правильно скопировали? Так, как написано, не должно работать. Кастить к unsigned надо до умножения (точнее деления).

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 23:33 
Да, правильно скопировано, но если и так написать
unsigned long p = 1+ (N*(N+1)/2);
работать тоже будет.

А почему неправильно? А не будет преобразование выражения (N+1) сразу к unsigned long (т.к. p такого типа) ?

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение06.11.2011, 00:01 
Да, всё правильно. Я не заметил, что тип N вы изменили на unsigned. Теперь преобразование типов не нужно. p тоже можно объявить просто unsigned.
Надо ещё формат ввода и вывода привести в соответствие с типом переменных.

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение06.11.2011, 00:22 
А вот если я просто пишу unsigned, он сколько битов выделяет?

Формат вывода вот так: printf("%u", p);, а формат ввода на что заменить надо?

 
 
 
 Re: Помогите разобраться с типами данных
Сообщение06.11.2011, 07:11 
_Student в сообщении #499954 писал(а):
А вот если я просто пишу unsigned, он сколько битов выделяет?
По стандарту - как минимум 16. Реально - 32.

_Student в сообщении #499954 писал(а):
Формат вывода вот так: printf("%u", p);, а формат ввода на что заменить надо?
Если так и оставите unsigned long p, то можно не менять, а если исправите на unsigned p, то тоже %u.

 
 
 [ Сообщений: 13 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group