C# Как найти максимальное значение int не используя константу?
Нужно найти максимальное значение типа int, используя только математические вычисления,не зная вес типа данных, без константы MaxValue. Тот же вопрос к типу double.
Нужно найти максимальное значение типа int, используя только математические вычисления,не зная вес типа данных, без константы MaxValue. Тот же вопрос к типу double.
int maxInt = (int)Math.Pow(2, 8 * sizeof(int)) - 1; // для int
double maxDouble = Math.Pow(2, 8 * sizeof(double) - 12) * (1 - Math.Pow(2, -52)) * Math.Pow(2, 1023); // для double
Если я правильно понял ваш вопрос
Объяснение:
int:
double:
Не помню, допускают ли типы C#
переполнение, но в абстрактном языке можно найти максимум для int
так, если он допускает переполнение:
x = 1
x0 = x - 1
while(x > x0)
{
x0 = x
x *= 2
}
x = x0 - 1 + x0
То есть умножаем число в 2 раза пока оно не переполнится (уйдёт в минус). Максимум будет тогда в 2 раза умноженное число до переполнения, минус 1.
Для целых типов задача довольно простая, т.к. битовая структура числа однородна и все биты числа равнозначны. Битовое представление чисел со знаком и без знака не отличается, отличается только интерпретация этого представления. Для использования представления со знаком и инверсии чисел, используется так называемый дополнительный код и инверсия выполняется по правилу NOT(x)+1, для обеспечения единственности нуля. У такого подхода есть недостаток - наименьшее отрицательное число не может быть инвертировано в положительное, т.к. положительное число такой величины отсутствует, но есть и достоинство - старший бит становится индикатором знака числа, однако, в отличие от дробных чисел, нельзя просто изменить значение одного бита, чтобы получить из отрицательного положительное и наоборот.
Для поиска граничных значений достаточно использовать беззнаковое представление интересующего типа, операцию битового сдвига влево с последующим добавлением единицы битовым OR. Таким образом мы найдем максимальное значение беззнакового представления, а из него максимум и минимум для знакового представления, например так:
uint test = 1;
uint tmp;
do{
tmp = test;
test = (test << 1) | 1;
}
while (test != tmp);
Console.WriteLine($"uint max value = {test}");
Console.WriteLine($"int min value = {-(long)(test/2)-1}");//тут нужно явное приведение
//к знаковому типу для проверки типа ulong, т.к. он является самым большим из доступных
//и не может быть преобразован в более емкий тип со знаком автоматически.
Console.WriteLine($"int max value = {test/2}");
А вот для двоичных дробных чисел коими являются float и double задача общего решения не имеет, т.к. нужно заранее точно знать не только разрядность числа, но и количество, размер, взаимное расположение и назначение групп битов в числе, которые регламентирует стандарт IEEE-754.
Как частное решение с опорой на знание стандарта IEEE-754 можно посчитать длину группы бит экспоненты и сделать вывод о том, к какому типу из стандарта относится проверяемый тип. Сделать это можно например так:
var x = 1.0f;
int k = 0;
do
{
k += 1;
x *= 2;
}
while (x != x / 0.0); //тут можно было взять константу "Infinity",
//но ее легко получить простым делением на 0
var expLen = Math.Log(k, 2) + 1;
Console.WriteLine($"Exponent length {expLen} bit, x is {(expLen == 8 ? "float" : "double")}");
В обоих примерах начальное значение для проверяемого типа должно быть равно единице, т.к. мы исследуем не значения, а сам тип переменной.