У меня возникает интересная ошибка сегмента в следующей функции, когда я даю ей число, очень близкое к 1.0. В частности, когда число будет округлено до 1,0 с точностью FLOATING POINT.
double get_random_element(double random_number)
{
if (random_number <= 0.0 || random_number >= 1.0)
throw std::runtime_error("Can't have a random number not on the range (0.0, 1.0)");
return -log(-log(random_number));
}
Если random_number равен 1.0, тогда log (1.0) = 0.0, а логарифм нуля - это неопределенное вычисление, приводящее к ошибке сегмента. Однако я мог подумать, что проверка ошибок в первой строке предотвратила бы это. Ddebugging показывает, что число, очень близкое к 1, пройдет проверку ошибок, но все равно вернет 0 из функции журнала, что заставляет меня поверить, что функция журнала использует только одну точность с плавающей запятой.
мои включения заключаются в следующем, поэтому я могу только предположить, что использую журнал из math.h
#include <string>
#include <math.h>
#include <sstream>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#include <utility>
ОБНОВЛЕНИЕ: как уже указывалось, простое решение - просто использовать число с плавающей запятой в качестве аргумента, и если передано число, равное 1.0f, просто удалить std :: numeric_limits :: epsilon (), чтобы получить число, которое может быть безопасно перешел в двойное бревно.
Но вопрос, на который я хотел бы получить ответ, заключается в том, почему вызов двойного журнала числа, близкого, но не равного 1, терпит неудачу.
ОБНОВЛЕНИЕ 2: после воссоздания этой проблемы в тестовом проекте я думаю, что проблема на самом деле во входных данных. Если я пройду
double val = 1.0 - std::numerical_limits<double>::epsilon();
У меня нет проблем с функцией. Однако на самом деле я передаю
boost::mt19937 random_generator;
double val = (random_generator()+1)/4294967297.0;
где random_generator предназначен для возврата числа в диапазоне [0, 2 ^ 32 - 1] == [0,4294967295]. Поэтому я решил ввести максимально возможное возвращаемое значение
double val = (4294967295+1)/4294967297.0;
который быстро дал мне предупреждение о переполнении unsigned int и, конечно же, сгенерировал ноль. Я перекомпилирую следующее:
get_random_element((random_generator()+1.0)/4294967297.0);
и, надеюсь, это странное поведение разрешится.
ОБНОВЛЕНИЕ 3: я наконец нашел, что здесь происходит ... и, как обычно, все сводится к ошибке пользователя (я являюсь ошибкой). Был второй путь управления, ведущий к этому методу, который временно хранил значение типа double как число с плавающей запятой, а затем преобразовывал его обратно в значение double, в результате чего 0,999999999 округлялось до 1,0, а затем передавалось в функцию -log (-log (x)) и приводило к это упасть. Я до сих пор не понимаю, почему я проверяю
if (random_number <= 0.0 || random_number >= 1.0) throw runtime_error(blah)
не поймали ошибочный ввод до того, как он был передан в функции журнала?
::log
и предварительно обработайте исходный код для проверки - person sehe   schedule 16.05.2011double
и1.0f
? - person quamrana   schedule 16.05.2011r + std::numeric_limits<double>::epsilon() > 1
вместоr >= 1
? - person Alexandre C.   schedule 16.05.2011<random>
в C ++ 0x предоставляет вам экстремальные отклонения значений (и правильную семантику с плавающей запятой). - person Alexandre C.   schedule 16.05.2011