Округление двойной точности до одинарной точности: форсирование верхней границы

Я использую реализацию Mersenne Twister, которая предоставляет мне числа с двойной точностью.

http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/FORTRAN/fortran.html (реализация в Fortran 77 Цуёси Тада, я использую genrand_real2)

Однако мое приложение нуждается во избежании предупреждений при умножении чисел с разной точностью на случайное число одинарной точности. Итак, я написал небольшую функцию для преобразования между двумя типами данных:

    function genrand_real()

    real   genrand_real
    real*8 genrand_real2

    genrand_real = real(genrand_real2())

    return
    end

Я использую реальные и реальные *8, чтобы соответствовать коду, над которым я работаю. Он прекрасно работает большую часть времени (кроме того факта, что я не уверен, насколько быстрым является real()), однако он меняет верхнюю границу моего ГСЧ, поскольку преобразование изменяет [0,1) на [0,1]. Я никогда не думал об этом, пока у меня не было проблем с этим.

Мой вопрос заключается в том, как я могу эффективно обеспечить верхнюю границу или даже как написать функцию, аналогичную genrand_real2 (оригинальной), которая предоставляет мне реал с одинарной точностью. Я думаю, мне нужно только заменить делитель 4294967296.d0, но я не знаю, по какому количеству

  function genrand_real2()

  double precision genrand_real2,r
  integer genrand_int32
  r=dble(genrand_int32())
  if(r.lt.0.d0)r=r+2.d0**32
  genrand_real2=r/4294967296.d0

  return
  end

1 ответ

Решение

Размещенная вами функция НЕ генерирует случайные числа, она ограничивает только случайные целые числа (из genrand_int32()) к интервалу [0,1) путем деления на 2^32 (что в точности равно 4294967296) или добавления сначала 2 ^ 32, если целое число отрицательно. 2^32 - это число значений, которое может содержать стандартное целое число, наполовину отрицательное, наполовину положительное (приблизительно, в положительном конце отсутствует 1) и, следовательно, происходит от функции genrand_int32(),

Представьте, что у вас есть числа от -10 до 10 и вы хотите ограничить их интервалом [0,1]. Самое простое решение состоит в том, чтобы добавить 20 к отрицательным числам (таким образом, положительные остаются 0-10, а отрицательные становятся 10-20), а затем делятся на 20. Это именно то, что делает функция, просто с 2^31 вместо 10.

Если вам интересно, почему интервал для вашей функции равен [0, 1): поскольку для числа 0 также требуется место, а битовое представление может хранить только 2 ^ 32 числа, вы не можете иметь 2^31 отрицательных и 2^31 положительное число И 0. Решение состоит в том, чтобы опустить значение +2^31 (самое высокое положительное) и, следовательно, 1 исключается из вашего интервала.

Итак, чтобы свести все это к единой точности:

function genrand_real2()

real genrand_real2,r
integer genrand_int32
r=real(genrand_int32())
if(r.lt.0)r=r+2**32
genrand_real2=r/4294967296

return
end

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

Изменить: Вы уже сказали это сами, так что я просто повторяю для других людей: Для переносимости технически не рекомендуется использовать типы по умолчанию без указания точности. Так что вы должны сделать sp = selected_real_kind(6, 37) (sp для одинарной точности) где-то, а затем real(kind=sp)... а также 2.0_sp и так далее. Однако это скорее академический момент.

Другие вопросы по тегам