2013-03-22 2 views
1

Я пытаюсь лучше понять распределение значений поплавка на строке реального числа.Самый большой диапазон равномерно распределенных значений поплавка?

Я написал этот код, чтобы подсчитать количество равномерно распределенных представимых значений в диапазоне (-R, R), где R представляет собой мощность (также пытались с полномочиями 2):

public class Foo { 
    public static void main(String[] args) 
    { 
     for(int i=0; i<24; i++) 
     { 
      int count = 0; 
      float R = (float) Math.pow(10, i); //(2<<i); 
      float Rstep = Math.ulp(R); 
      for(float x = -R; x <= R; x+=Rstep) 
       count++; 
      System.out.println(R+" "+count+" "+Math.ulp(R)); 
     } 
    } 
} 

Я был удивлен разницей в результатах, т.е.

1.0 16777217 1.1920929E-7 
10.0 20971521 9.536743E-7 
100.0 26214401 7.6293945E-6 
1000.0 32768001 6.1035156E-5 
10000.0 20480001 9.765625E-4 
100000.0 25600001 0.0078125 
1000000.0 32000001 0.0625 

, как я бы пол-убедил себя число равномерно распределенных значений будет 16777216 (т.е. 1 < < 23 для 23-битной мантиссы, удвоенной из-за знакового бита).

Чтобы поставить определенную конкретность по этому вопросу - я пытаюсь построить модель (которая использует единицы СИ, точнее, на несколько порядков, например расстояние в км до нанометров), но должна отображать ее в пространстве с плавающей точкой (для загрузки в графический процессор). Поскольку это научная модель, мне нужно понять, где потеря точности. План состоит в том, чтобы привязать значения к равномерно распределенному диапазону - поэтому из приведенной выше таблицы привязка к диапазону (-1000,1000) даст мне 32768001 точные значения.

Кажется противоречащим мне, что в этих диапазонах будет так много различий, и почему мощность в 2 случаях ограничена.

Может ли кто-нибудь объяснить, как об этом думать?

веселит

+0

Я думаю, вы забыли про ноль. – alestanis

+0

спасибо - я не так беспокоюсь об этой потенциальной ошибке за один раз (хотя было бы хорошо понять) - больше дисперсия в 2 раза – user2152466

+0

Что вы подразумеваете под «равномерно распределенным»? Единственные интервалы, включая ноль, где значения «float» имеют равномерный интервал, составляют от -2 ** - 125 (от -2,35 до 38) до +2 ** - 125 и все его промежутки. В этом интервале интервал равен 2 ** - 149 (около 1,40e-45). Кроме того, размер шага варьируется; распределение представимых значений не является однородным. –

ответ

2

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

Ваша оценка «16777216 (т. Е. 1 < < 23 для 23-битной мантиссы, удвоенной из-за знакового разряда)» - это только половина того, что вы можете ожидать. Лучше всего начать с числа, которое выглядит как -0x1.FFF ... pX в шестнадцатеричном виде, то есть противоположно числу чуть ниже двух. При повторном добавлении начального ULP вы действительно пройдете все значения знака с показателем X. Это 1 < < 23 шага, как вы это делали. Когда вы закончите с этим, вы станете наполовину близким к нулю, когда вы начнете. Такое же количество шагов приведет вас к нулю (с показателями ниже X), а затем удвоить количество шагов для положительных значений.

Итак, это 1 < < 25 (~ 32000000) или равномерно распределенные поплавки, которые могут быть найдены между любыми близкими к силе двух и противоположными. Вы получаете это количество шагов с 1000, потому что 1000 просто находится под мощностью двух 1024.

Худший случай, как вы заметили, состоит в том, чтобы начать с числа чуть выше двух, скажем 0x1.00001pX. Затем вы почти не меняете значения с показателем X, но вместо этого сразу начинаете посещать значения с более низкими показателями. Вы в конечном итоге посещения только в два раза меньше значения, как вы бы, если бы вы начали с 0x1.FFF ... РХ


Примечание: обозначение -0x1.123defpX следует интерпретировать как -0x1.123def * 2^X. Возможно, ваш язык программирования принимает его для ввода и/или вывода значений с плавающей запятой. Для повторного итерации это очень удобно, когда вы пытаетесь понять, что происходит.