Подтвердить что ты не робот

Сколько уникальных значений существует от 0 до 1 стандартного поплавка?

Я предполагаю, что другой способ формулировки этого вопроса состоит в том, что десятичное место вы можете использовать при использовании float, который будет только от 0 до 1?

Я попытался его обработать, посмотрев MSDN. Который говорит, что точность составляет 7 цифр. Я думал, что это означает, что он может отслеживать изменения 0.0000001.

Однако, если я это сделаю:

float test = 0.00000000000000000000000000000000000000000001f;
Console.WriteLine(test);

Он выписывает 9.949219E-44

Если я добавлю больше нулей, он выведет 0.

Я уверен, что здесь что-то отсутствует, поскольку эта степень точности кажется массово неправильной. В основном, как float размером 32 бита, и только от 0-1 на этом уровне точности содержит 1e + 44 возможных номеров...

4b9b3361

Ответ 1

Сколько уникальных значений существует от 0 до 1 стандартного поплавка?

На самом деле это не вопрос, на который вы хотите получить ответ, но ответ состоит в том, что не включая 0 и 1 себя, что в этом диапазоне есть 2**23 - 1 субнормальные числа и 126 * 2**23 нормальные числа, для всего 127 * 2**23 - 1 или 1,065,353,215.

Но учтите, что эти числа не равномерно распределены на интервале между 0 и 1. Использование "дельта" 1f / 1065353215f в цикле от 0f до 1f не будет работать для вас.

Если вы хотите перейти от 0.0 до 1.0 с помощью экваториальных шагов (десятичной) формы 0.00... 01, возможно, вы должны использовать decimal вместо float. Он будет точно представлять цифры.

Если вы придерживаетесь float, попробуйте с 0.000001 (в десять раз больше, чем предлагаемое значение), но обратите внимание, что ошибки могут возникать при выполнении очень многих дополнений с не представимым числом.

Также обратите внимание: Существует несколько доменов, в которых вы не можете даже рассчитывать на первые семь значащих десятичных цифр float. Попробуйте, например, сохранить значение 0.000986f или 0.000987f переменной float (убедитесь, что оптимизация не содержит значения в "более широком" месте хранения) и выпишите эту переменную. Первые семь цифр не идентичны 0.0009860000 соответственно. 0.0009870000. Снова вы можете использовать decimal, если вы хотите работать с числами, десятичные разложения которых "коротки".

Изменить: Если вы можете использовать "двоичный" шаг для своего цикла, попробуйте:

float delta = (float)Math.Pow(2, -24);

или эквивалентно как литерал:

const float delta = 5.96046448e-8f;

Хорошая вещь об этой дельте состоит в том, что все значения, которые вы получаете через цикл, точно представлены в вашем float. Как раз перед (под) 1f, вы будете делать как можно меньше возможных шагов для этой величины.

Ответ 2

Это 7 значащих цифр, то есть при записи в экспоненциальной нотации вы игнорируете экспонента.

0.0000000000000000001234567 имеет такое же количество значащих цифр, что и 12345670000000000000, только с другим показателем. Это волшебство, которое позволяет номерам с плавающей запятой хранить действительно маленькие и действительно большие числа.

Что касается точно количества возможных чисел для float в (0, 1), я не могу сказать точно прямо сейчас. У вас есть 23-битная мантисса, поэтому 2 23 возможные состояния. Тогда есть 8-битный показатель, и если я не ошибаюсь, примерно половина его возможных значений приведет к числу от 0 до 1. Который должен оставить вас примерно с 2 23 + 7= 2 30 возможных значений в этом диапазоне. Если что-нибудь, что возможно, верхняя граница, а не точное значение. Мне нужно будет проконсультироваться с документацией о более тонких деталях, чтобы точно знать (и, возможно, пересмотреть математику выше, которая может пропустить несколько точек).

Ответ 3

Я написал эту очень глупую программу, и она дает ответ 1065353217, который действительно просто застенчив 2 30 (1073741824). Вычитайте 2 из этого числа, если вы искали все числа, не содержащие 0 и 1. Кстати, наименьшее ненулевое число выглядит как 1.401298E-45.

class Program
{
    public unsafe static int Search()
    {
        int i = 0;
        float* f = (float*)&i;
        while (*f >= 0 && *f <= 1)
        {
            f = (float*)&i;
            i++;
        }

        return i;
    }

    static void Main(string[] args)
    {
        Console.WriteLine(Search());
        Console.ReadLine();
    }
}

Ответ 4

Положительные значения с плавающей запятой упорядочены так же, как и их кодировки. 0.0f - 0x00000000. 1.0f - 0x3f800000. Таким образом, существуют значения 0x3f800000 - 1 с плавающей запятой, которые лежат строго между ними, или 1,065,353,215.

Если вы хотите включить конечные точки в свой счет, имейте в виду, что есть два кодировки нуля.

Имейте в виду, что значения с плавающей запятой не равномерно распределены. Разница между 1.0f и следующим меньшим числом равна 2**-24, тогда как разница между 0.0f и следующим большим числом 2**-149. Если вы хотите увеличивать поплавок от 0 до 1 с помощью единых шагов, наименьший размер шага, который вы можете использовать, - 2**-24.

Ответ 5

Поскольку тип с плавающей запятой имеет 4 байтовых данных, мы можем проверить все возможные варианты всех 4 байтов (0-255) с помощью приведенного ниже кода и подсчитать, сколько из них находится в диапазоне [0,1] - включительно
Таким образом, ответ будет 1065353218

Постскриптум Выполнение кода может занять до 2-3 минут в зависимости от компьютера.

public static void Main()
    {
        long count = 0;
        //byte checking sub/method
        void CheckThisBytes(byte ii, byte jj, byte kk, byte ll)
        {
            var data = new[] {ii, jj, kk, ll};
            var f = BitConverter.ToSingle(data, 0);
            //is f in range ?
            if (f >= 0.0 && f <= 1.0)
            {
                count++;
            }
        }
        const int max = 255;
        // generate all possible cases 
        for (var i = 0; i <= max; i++)
        {
            for (var j = 0; j <= max; j++)
            {
                for (var k = 0; k <=max; k++)
                {
                    for (var l = 0; l <= max; l++)
                    {
                        //check if current float is in range
                        CheckThisBytes((byte) i, (byte) j, (byte) k, (byte) l);
                    }
                }
            }
        }
        Console.WriteLine("\n Count:" + count);
        Console.ReadLine();
        //result will be  1065353218
    }