Сколько различных чисел с плавающей запятой в определенном диапазоне?

Сколько представимых чисел с плавающей запятой находится между 0.0 и 0.5? И сколько представимых чисел с плавающей запятой находится между 0.5 и 1.0? Меня больше интересует математика, лежащая в основе этого, и мне нужен ответ для floats и doubles.


person Arlen    schedule 16.01.2012    source источник
comment
Подсказка: сколько битов используется для представления этого дробного диапазона?   -  person Mitch Wheat    schedule 16.01.2012
comment
Я не помню доказательства навскидку, но вы можете найти ответ в docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html или Floating-point-gui.de.   -  person Crashworks    schedule 16.01.2012
comment
не забывайте считать -0.0 :-)   -  person franji1    schedule 16.01.2012
comment
это будет полностью зависеть от того, сколько битов вы должны представить.   -  person Gustavo F    schedule 16.01.2012
comment
От 0,5 до 1,0 было бы довольно легко вычислить. От 0,0 до 0,5 - не все так просто.   -  person Hot Licks    schedule 16.01.2012
comment
Также (очень) тесно связан: stackoverflow.com/questions/5015133/   -  person Nemo    schedule 16.01.2012


Ответы (5)


Для поплавков IEEE754 это довольно просто. Запустите онлайн-калькулятор с плавающей запятой и продолжайте читать.

Все чистые степени двойки представлены мантиссой 0, которая на самом деле 1.0 из-за подразумеваемого ведущего 1. Показатель корректируется смещением, поэтому 1 и 0,5 равны соответственно 1,0 2 0 и 1,0 2 1 или в двоичном виде:

      S    Ex + 127    Mantissa - 1                Hex

1:    0    01111111    00000000000000000000000     0x3F800000
      +     0 + 127    1.0

0.5:  0    01111110    00000000000000000000000     0x3F000000
      +    -1 + 127    1.0

Поскольку числа с плавающей запятой, представленные в этой форме, упорядочены в том же порядке, что и их двоичное представление, нам нужно только взять разность целого значения двоичного представления и сделать вывод, что существует 0x800000 = 2 23 , т.е. 8 388 608 значений с плавающей запятой одинарной точности в интервале [0,5, 1,0).

Точно так же ответ: 2 52 для double и 2 63 для long double.

person Kerrek SB    schedule 16.01.2012
comment
... и есть 0x3F000000 представимые числа с плавающей запятой одинарной точности между 0.0 и 0.5, что превышает 1 миллиард. Хороший! - person Arlen; 16.01.2012

Число с плавающей запятой в формате IEEE754 находится в диапазоне от 0,0 (включительно) до 0,5 (исключая) тогда и только тогда, когда бит знака равен 0, а показатель степени равен < -1. Биты мантиссы могут быть произвольными. Для float это делает допустимым показателем 2^23 чисел для double 2 ^ 52. Сколько существует допустимых показателей степени? Для float минимальный показатель степени для нормализованных чисел составляет -126, для double это -1022, поэтому есть

126*2^23 = 1056964608

float значения в [0, 0.5) и

1022*2^52 = 4602678819172646912

double значений.

person Daniel Fischer    schedule 16.01.2012

Для 0,0..0,5: вам нужно позаботиться об экспонентах от -1 до минимально возможного, а затем умножить, сколько вы получите, на количество различных значений, которые вы можете представить в мантиссе.

Для каждого значения в этом диапазоне, если вы удвоите его, вы получите значение в диапазоне 0,5..1,0. А удвоение - это просто увеличение показателя степени.

Вам также нужно беспокоиться о ненормализованных числах, где мантисса используется не для представления 1.x, а для 0.x, и, таким образом, все они будут в вашем нижнем диапазоне, но не могут быть удвоены путем увеличения показателя степени (поскольку конкретное значение показателя степени используется, чтобы указать, что значение ненормализовано).

person Scott Hunter    schedule 16.01.2012
comment
Для каждого значения в этом диапазоне, если вы удвоите его, вы получите значение в диапазоне 0,5..1,0. э, нет, вам нужно добавить 0,5, что означает, что все числа ниже ulp(0.5) станут одинаковыми (0,5), для диапазона 0,5..1 все показатели равны -1 - person ratchet freak; 16.01.2012
comment
Упс - я думал об этом в другом направлении (переход от диапазона 0,5..1,0 и уменьшение всего вдвое, что БУДЕТ отображать все в нижнем диапазоне). - person Scott Hunter; 16.01.2012
comment
да, но в нем не было бы ВСЕХ чисел, особенно тех ‹0,25 - person ratchet freak; 16.01.2012
comment
Никогда не говорил, что это было, но хорошая характеристика того, где разрыв. - person Scott Hunter; 16.01.2012

Сам по себе это не ответ, но вы можете получить некоторую информацию из nextafter функция. Что-то вроде этого должно помочь вам ответить на ваш вопрос, хотя вам придется вычислить математику самостоятельно:

float f = 0;
while(f < 0.5)
  {
    print("%f (repr: 0x%x)\n", f, *(unsigned *)&f);
    f = nextafterf(f, 0.5);
  }
person Chris Lutz    schedule 16.01.2012
comment
прежде, чем вы попытаетесь сделать эту половину представимых чисел с плавающей запятой, находятся между -1 и 1 для числа с плавающей запятой, равным 2 миллиардам (или 1 миллиард между 0 и 1), если удвоить это число в квадрате, если вы начнете считать, вы немного подождете - person ratchet freak; 16.01.2012
comment
@ratchetfreak - Верно, но если вы не знаете основную математику (например, я), вы, вероятно, можете начать собирать по кусочкам шаблон максимум с первых двадцати, а затем все, что вам действительно нужно знать, - это начальная и конечная точки. Но да, лучше, если вы знаете математику. - person Chris Lutz; 16.01.2012

Керрек дал лучшее объяснение :)

На всякий случай вот код для игры с другими интервалами
http://coliru.stacked-crooked.com/a/7a75ba5eceb49f84

#include <iostream>
#include <cmath>

template<typename T>
unsigned long long int floatCount(T a, T b)
{
    if (a > b)
        return 0;

    if (a == b)
        return 1;

    unsigned long long int count = 1;

    while(a < b) {
        a = std::nextafter(a, b);
        ++count;
    }

    return count;
}

int main()
{
    std::cout << "number of floats in [0.5..1.0] interval are " << floatCount(0.5f, 1.0f);    
}

отпечатки

number of floats in [0.5..1.0] interval are 8388609
person Péter Joó    schedule 01.02.2016