У меня есть строчка:
std::uniform_real_distribution<T> distribution(std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max());
Он компилируется, но вылетает при отладке (VS 2017CE). Я предполагаю, что согласно документации std::uniform_real_distribution:
Requires that
a ≤ bandb-a ≤ std::numeric_limits<RealType>::max()
когда мой b - это ::max(), а a - это ::lowest(), условие:
b-a ≤ std::numeric_limits<RealType>::max()
не выполняется, поскольку b-a в основном удваивает значение max. Есть ли какой-нибудь способ обойти это, чтобы я сохранил такой широкий диапазон чисел? ::min() работает отлично, но пропускает отрицательные значения. Проблема возникает только для чисел с плавающей запятой.
@hellow Именно так. Может быть немного меньше, но максимально широким.
Возможно, есть более разумное решение, но если все не удается, вы можете использовать два диапазона (отрицательная и положительная полуось) и случайным образом выбрать один для опроса. Или, что эквивалентно IEEE754, используйте [0, max] и случайным образом меняйте знак.
У меня есть ответ, но я хотел бы спросить, какое поведение вы ищете в первую очередь. Диапазон [lowest, max) будет давать большую часть своих результатов ближе к двум концам, поскольку на концах гораздо больше чисел, чем в середине. Вы хотите такого поведения или хотите, чтобы меньшие числа имели одинаковые шансы появиться?
@NathanOliver Большинство результатов, имеющих большую величину, можно было бы ожидать при использовании равномерного распределения, не так ли?
@NathanOliver Мне нужны значения по краям диапазона. Мне не нужно какое-то конкретное число, только максимальная ширина диапазона.
@BaummitAugen Некоторые люди не ожидают такого поведения





Одно простое решение, по крайней мере для обычных чисел с плавающей запятой IEEE-754, - это случайное изменение знака случайного неотрицательного числа:
std::uniform_real_distribution<T> distribution(0.,
std::numeric_limits<T>::max());
auto rn = distribution(eng);
return someRandomFlag ? rn : -rn;
где someRandomFlag выбирается единообразно из {true, false}.
Думаю, я пойду на это, потому что это просто и чисто. Спасибо. Однако я подожду и приму это как решение, потому что мне просто любопытно, почему это вообще происходит, и, возможно, кто-то узнает.
@PStarczewski Вы уже знаете, почему это происходит. uniform_real_distribution требует, чтобы b-a <= max.
Обратите внимание, что это может привести к смехотворно небольшому перевесу 0, поскольку 0 и -0 равны.
@ Yakk-AdamNevraumont пока 0. == -0., Они не совпадают.
@DanM. • одно и то же число (математически говоря), разные представления. -0. встречается в некоторых крайних случаях. Лечился так же ... в основном. Иногда бывает сложно различить их, когда такое различение желательно.
«Математика» здесь не актуальна, поскольку числа с плавающей запятой / добулы не являются вещественными числами. Для компьютеров все иначе. Это, вероятно, не имеет значения для большинства целей, но это стоит знать. Например, хотя uniform_real_distribution является «однородным», у некоторых чисел будет гораздо больше шансов быть выбранными, чем у других, только потому, что распределение с плавающей запятой не является равномерным.
@DanM. Каждое число с плавающей запятой можно рассматривать как представление диапазона действительных чисел; Теоретически равномерное реальное распределение может дать каждому числу с плавающей запятой шанс, соизмеримый с мерой представленного набора действительных чисел. «Математика» здесь очень уместна; при игнорировании получаешь ерунду.
@Yakk - Adam Nevraumont да, но вы получите неоднородные числа, которые будут одинаковыми только в отношении представленных интервалов. Это важное различие. Это обсуждение возникло из-за «смехотворно небольшого завышения 0». Если мы начнем говорить о «весах», больше не имеет смысла говорить о реальных числах. компьютерные двойники уже сильно неоднородны (с точки зрения «вероятности генерировать это число») с любым таким распределением.
@DanM. Вероятность на бесчисленных множествах выражается как меры подмножеств; разделение вещественных чисел на классы эквивалентности и использование чисел с плавающей запятой в качестве имени класса эквивалентности имеет смысл и является разумным способом говорить о реальном равномерном распределении значений с плавающей запятой (или действительно о любом реальном равномерном распределении; все действительные числа имеют вероятность 0 выбирается в равномерном распределении). Все это имеет смысл и прямо следует из «Математики». Ваши возражения, кажется, указывают на заблуждение относительно теории меры и теории вероятностей, что является обычным явлением.
@Yakk - Адам Неврамонт, нет бесчисленных наборов на ПК. И не имеет значения, «проверяет» ли лежащая в основе математика (я не сомневаюсь в этом), но программист не имеет дела с идеальными математическими системами. Для программиста может быть очень удивительно узнать, что какое-то значение X генерируется в 1000 раз больше, чем какое-то другое значение Y в предположительно однородном распределении (его не волнует, принадлежит ли оно к классу, представляющему интервал в 1000 раз больше или нет)
@DanM. Да, программисты, которые не понимают, что означает «равномерное реальное распределение», не поймут, что он делает. Возможно и ожидаемо, что «равномерное реальное распределение» означает «равномерное реальное распределение». Действительные числа, которые представляет данное значение с плавающей запятой (т. Е. Округляются до этой плавающей запятой), четко определены в стандарте IEEE. Тем не менее, это непродуктивно. До свидания.
Один из способов сделать это - использовать диапазон [-1, 1], а затем умножить его на std::numeric_limits<T>::max(), чтобы получить фактическое число. Это позволяет удовлетворить требования b-a ≤ std::numeric_limits<RealType>::max().
auto dis = std::uniform_real_distribution<T> dis(-1, std::nextafter(1, std::numeric_limits<T>::max()));
return dis(eng) * std::numeric_limits<T>::max();
Это не даст вам всех возможных значений с плавающей запятой, но даст вам хорошее количество из них, распределенных, как uniform_int_distribution.
Вы уверены, что этим можно достичь всех возможных значений?
@BaummitAugen Я почти уверен, что это не так, но он ведет себя как uniform_int_distribution для диапазона значений. Зависит от того, как ОП на самом деле хочет, чтобы результаты распределялись.
Это кажется противоречивым. Для равномерного распределения, скажем, в диапазоне double, каждое число должно иметь положительную вероятность (которая, конечно, зависит от его величины).
@BaummitAugen Я никогда не видел реализации uniform_real_distribution, которая действительно достигла бы этого свойства. Нормальный подход - это просто u01 * (max-min) + min.
@Sneftel Возможно, никогда не проверял подробно. Но так и должно быть, по крайней мере, в теории.
Для моих нужд это решение тоже подходит. Спасибо большое. Я оставлю его открытым на время, чтобы посмотреть, знает ли кто-нибудь, почему это вообще происходит.
@PStarczewski Знаешь, почему что происходит?
@PStarczewski это (сбой) происходит из-за того, что вы нарушаете задокументированные требования дистрибутива?
@ Yakk-AdamNevraumont Я не уверен. Я только что протестировал его на linux и отлично работает в отличие от windows. Не могу понять, почему.
@PStarczewski Нарушение контракта является неопределенным поведением. В контракте указано, что это b-a ≤ std::numeric_limits<RealType>::max(), и если вы его нарушите, все ставки отключены. Он мог работать, он мог не компилироваться, он мог дать сбой, он мог дать вам неправильные результаты, он мог выпустить моих собак со двора, и мне пришлось потратить полчаса, преследуя их. Неопределенное поведение означает, что он может делать то, что хочет.
То есть, я думал, что знаю, почему он не работает, однако из любопытства протестировал его на Linux и работал отлично. Так что теперь я не уверен, был ли мой диагноз верным.
@NathanOliver Спасибо за объяснение!
Итак, вы хотите равномерного распределения по всему диапазону
T?