Есть ли способ в C / C ++ вычислить максимальную степень двух, которая может быть представлена определенным типом данных, используя оператор sizeof?
Например, скажем, у меня есть unsigned short int
, Его значения могут варьироваться между 0
а также 65535
,
Поэтому максимальная мощность двух, что unsigned short int
может содержать 32768
,
Я передаю это unsigned short int
к функции, и у меня есть (на данный момент) и алгоритм, который выглядит следующим образом:
if (ushortParam > 32768) {
ushortParam = 32768; // Bad hardcoded literals
}
Однако в будущем я, возможно, захочу изменить тип переменной, чтобы включить большие степени двух. Существует ли независимая от типа формула с использованием sizeof (), которая может обеспечить следующее:
if (param > /*Some function...*/sizeof(param) )
{
param = /*Some function...*/sizeof(param);
}
Обратите внимание, что для параметра никогда не потребуется точность с плавающей точкой — только целые числа.
Установка старшего значащего бита вашей переменной для этого размера параметра даст вам наибольшую степень 2.
1 << (8*sizeof(param)-1)
Как насчет:
const T max_power_of_two = (std::numeric_limits<T>::max() >> 1) + 1;
Чтобы получить максимальную степень 2, представляемую определенным целочисленным типом, вы можете использовать limits.h
вместо sizeof
оператор. Например:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
int main() {
int max = INT_MAX;
int hmax = max>>1;
int mpow2 = max ^ hmax;
printf("The maximum representable integer is %d\n",max);
printf("The maximum representable power of 2 is %d\n",mpow2);
return 0;
}
Это всегда должно работать, поскольку всегда определяется правильное смещение положительного целого числа. Цитирование из стандартного раздела C 6.5.7.5 (Оператор побитового сдвига):
Результат E1 >> E2 является E1 право смещенной E2 битовые позиции. Если E1
имеет тип без знака или если E1 имеет подписанный тип и неотрицательный
значение, значение результата является неотъемлемой частью отношения
E1 делится на количество, 2 возведенное в степень E2.
Если использование sizeof
обязательно вы можете использовать:
1 << (CHAR_BIT*sizeof(param)-1)
для целых типов без знака и:
1 << (CHAR_BIT*sizeof(param)-2)
для целых типов со знаком. Строки выше будут работать только в случае целочисленных типов без битов. Часть стандарта C, обеспечивающая работу этих линий, приведена в разделе 6.2.6.2. Особенно:
Для целых типов без знака, кроме символ без знака, биты
представление объекта должно быть разделено на две группы: биты значения и
биты заполнения (не должно быть ни одного из последних). Если есть N
биты значения, каждый бит должен представлять различную степень 2 между 1
и 2N-1, так что объекты этого типа должны быть способны
представляет значения от 0 до 2N — 1, используя чистый двоичный файл
представление; это должно быть известно как представление значения.
гарантирует первый метод для работы, пока:
Для целочисленных типов со знаком биты представления объекта должны
разделить на три группы: биты значения, биты заполнения и знак
немного. Там не должно быть никаких битов заполнения; должен быть ровно один
знак бит.…
Допустимое (не trap) представление объекта целого типа со знаком
где знаковый бит равен нулю, является действительным представлением объекта
соответствующий тип без знака, и должен представлять то же значение.
объясняет, почему во второй строке дан правильный ответ.
Принятый ответ, вероятно, будет работать на платформах Posix, но не является общим C / C ++. Предполагается, что CHAR_BIT равен 8, не указывает тип и предполагает, что тип не имеет битов заполнения.
Вот более общие версии для любых / всех целочисленных типов без знака и не требуют включения каких-либо заголовков, зависимостей и т.д .:
#define MAX_VAL(UNSIGNED_TYPE) ((UNSIGNED_TYPE) -1)
#define MAX_POW2(UNSIGNED_TYPE) (~(MAX_VAL(UNSIGNED_TYPE) >> 1))
#define MAX_POW2_VER2(UNSIGNED_TYPE) (MAX_VAL(UNSIGNED_TYPE) ^ (MAX_VAL(UNSIGNED_TYPE) >> 1))
#define MAX_POW2_VER3(UNSIGNED_TYPE) ((MAX_VAL(UNSIGNED_TYPE) >> 1) + 1)
Стандарты, даже C90, гарантируют, что приведение -1 к типу без знака всегда дает максимальное значение, которое может представлять тип. Отсюда все побитовые операторы выше хорошо определены.
http://c0x.coding-guidelines.com/6.3.1.3.html
6.3.1.3 Целые числа со знаком и без знака
682 Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.
683 В противном случае, если новый тип является беззнаковым, значение преобразуется путем многократного сложения или вычитания более одного максимального значения, которое может быть представлено в новом типе, до тех пор, пока значение не окажется в диапазоне нового типа.
684 В противном случае новый тип подписывается, и значение не может быть представлено в нем;
685 либо результат определяется реализацией, либо определяется сигнал реализации.
Максимальное значение типа без знака на единицу меньше степени 2 и имеет все установленные биты значения. Вышеприведенные выражения приводят к установке самого старшего бита, который является максимальной степенью 2, которую может представлять тип.
http://c0x.coding-guidelines.com/6.2.6.2.html
6.2.6.2 Целочисленные типы
593 Для целых типов без знака, кроме беззнаковых символов, биты представления объекта должны быть разделены на две группы: биты значения и биты заполнения (не должно быть ни одного из последних).
594 Если имеется N битов значения, каждый бит должен представлять различную степень 2 от 1 до 2 ^ (N — 1), так что объекты этого типа должны быть способны представлять значения от 0 до 2 ^ N — 1 с использованием чисто двоичное представление;
595 это должно быть известно как представление значения.
596 Значения любых битов заполнения не указаны.