2012-01-02 3 views
2

Функция питания (написана в C++) ...Почему эта функция не превышает значение 2^31?

long power (long a, long b){ 
    long result=1l; 
    for (int i = 0;i<b;i++){ 
     result*=a; 
    } 
    return result; 
} 

Теперь я немного выходного тестирования ...

cout<<power(2l,2l)<<endl; 
cout<<power(2l,4l)<<endl; 
cout<<power(2l,31l)<<endl; 
cout<<power(2l,32l)<<endl; 
cout<<power(2l,61l)<<endl; 

Выход:

4 
16 
-2147483648 
0 
0 

Ну, кажется, некоторая проблема с длинным возвратом к 32-битовому размеру (вместо того, чтобы оставаться как 64-битный). Мне интересно, почему это не работает, но если я использую тип long long, все работает нормально.

Некоторые дополнительные сведения:

Я использую C++ и компилятор MinGW
Я бегу 64-разрядной ОС (Windows 7)

UPDATE:

Вы, ребята, здорово! Никогда не думал, что это будет происходить.

Я только что проверил некоторые произвольные ТПР с помощью sizeof и это то, что я нашел ...

cout<<sizeof(long)<<" "<<sizeof(int)<<" "<<sizeof(char)<<" "<<sizeof(long long)<<" "<<sizeof(uint64_t)<<endl; 

Выход:

4 4 1 8 8 

Таким образом, это выглядит, как мой long и int оба 32 бита в размере. Еще несколько игр показывают, что тип intmax_t также является 64-битным. Практически каждый отдельный PDT ограничен 64 битами, поэтому, если мне когда-либо понадобилось представлять 128-битное целое число, имеет ли C++ встроенный класс для этого (что-то похожее на BigInteger в Java)?

+4

Dont guess - напечатайте значения sizeof (long) и sizeof (int), чтобы узнать, насколько они велики –

+1

Если вы хотите задать новый вопрос, я бы рекомендовал создать новый вопрос (или, еще лучше, [ поиск предыдущего вопроса по теме] (http://stackoverflow.com/search?q= [c% 2B% 2B] + большая + целочисленная + библиотека)). Вот одна быстрая ссылка: http://gmplib.org/ –

ответ

6

По-видимому, тип long - это 32 бита в вашей среде.

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

EDIT

Чтобы ответить на ваш второй вопрос (это C++ имеет встроенный класс для 128-битных целых чисел?): Нет, это не так. Вернее, это не требует. Однако, если бы реализация обеспечила одно, вы могли бы использовать что-то вроде uint128_t. Лично я не видел никакой системы, которая это делает. Существуют сторонние библиотеки, такие как GMP, которые обеспечивают эту функциональность.

+0

добавлена ​​ссылка на внешнюю информацию о переполнении целых чисел. –

+0

Небольшой комментарий: переполнение по целому знаку со знаком является неопределенным поведением, поэтому '0' является одним из возможных входов. Вместо использования целого числа без знака (например, 'unsigned long') была бы обертка, и результат мог бы быть не' 0' (но '1') –

+0

Большой металл может иметь их. Я использовал несколько (менее 5) исследовательских машин, которые имели int 128. –

0

В C++, а также в C размер int зависит от архитектуры, и все это правда, но этот улов заключается в том, что 32-разрядная подписка int проходит между -2^31 и (2^31- 1), нет 2^31. Вы действительно переполняете 32-битное число. Вместо этого вы должны использовать unsigned int. Это происходит между 0 и (2^32-1).

+0

Что вы говорите имеет смысл, но мои ints все еще 32-бит: S –

+0

Изменен мой ответ. – Phonon

+0

Yup, что вы говорите, мертв, за исключением того, что мне нужны числа размером 2^61, где даже беззнакового int не хватит. –

1

A.

cout<<sizeof(long); 

Чтобы увидеть, что это 32-бит.

B. Я думаю, что это проблема с определением вашего проекта. даже если вы работаете на 64-битной машине, он может скомпилировать 32-битную программу, чтобы вы могли использовать ее как на 32, так и на 64, но на машинах.
и длинный всегда размер указателя ...

C. uint64_t - лучшая практика.

0

Ну длинный тип занимает 32 бита, поэтому максимальное положительное значение - 4294967296-1. Но ваша функция вычисляет значение 5842587018385982521381124421 = 21^21.

+0

Фактически это было 2l^2l, где «l» (L в заглавной форме) обозначает тип 'long' –