2014 dxdy logo

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

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




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


17/10/10
49
Вечер добрый всем!

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

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 
Аватара пользователя


31/10/08
1244
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 


17/10/10
49
Не, так не работает: long int p = 1+ N*(long int(N)+1)/2;

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

 Профиль  
                  
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 22:14 
Аватара пользователя


31/10/08
1244
_Student
Кстати о птичках. Вы не указали какой ответ правильный, а какой нет. То есть какой хотите, что получаете?

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

 Профиль  
                  
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 22:19 


17/10/10
49
Считаю в СКА Maple 1+ N*(N+1)/2 при N = 65535 и получаю такой вот ответ: 2147450881. Он мне и нужен. А программа выводит 4294934529.

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

 Профиль  
                  
 
 Re: Помогите разобраться с типами данных
Сообщение05.11.2011, 22:49 
Аватара пользователя


31/10/08
1244
Вот смотри.
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 
Заслуженный участник


04/05/09
4587
_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 


17/10/10
49
"Почему у вас в результате получилось большое положительное число - отдельная история."
А почему оно получается? Причем верное получается, если просто вывести 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 
Заслуженный участник


04/05/09
4587
_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 


17/10/10
49
Да, правильно скопировано, но если и так написать
unsigned long p = 1+ (N*(N+1)/2);
работать тоже будет.

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

 Профиль  
                  
 
 Re: Помогите разобраться с типами данных
Сообщение06.11.2011, 00:01 
Заслуженный участник


04/05/09
4587
Да, всё правильно. Я не заметил, что тип N вы изменили на unsigned. Теперь преобразование типов не нужно. p тоже можно объявить просто unsigned.
Надо ещё формат ввода и вывода привести в соответствие с типом переменных.

 Профиль  
                  
 
 Re: Помогите разобраться с типами данных
Сообщение06.11.2011, 00:22 


17/10/10
49
А вот если я просто пишу unsigned, он сколько битов выделяет?

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

 Профиль  
                  
 
 Re: Помогите разобраться с типами данных
Сообщение06.11.2011, 07:11 
Заслуженный участник


04/05/09
4587
_Student в сообщении #499954 писал(а):
А вот если я просто пишу unsigned, он сколько битов выделяет?
По стандарту - как минимум 16. Реально - 32.

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

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 13 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group