Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Случайное число с исключением (http://www.flasher.ru/forum/showthread.php?t=174559)

Scorp2008 28.01.2012 13:06

Случайное число с исключением
 
Доброго дня.
Мне нужно получить случайное число в заданном диапазоне (ес-но функцией), но с исключением какого-либо числа, т.е. например любое число от 1 до 10, но только не 5. (1,2,3,4,6,7,8,9,10)... Имеется переменная в которой храниттся число исключение - idgame:int, также имеется функция рандома которая выдает случайное число в заданном диапазоне, а как сделать то что мне нужно - прошу помочь. Спасибо.

Функция рандома:
Код AS3:

public function random(min:Number, max:Number):Number {
  return Math.round(Math.random() * (max - min)) + min;
}


bav 28.01.2012 13:25

Первый, плохой, но рабочий вариант:
Код AS3:

public function random(min:Number, max:Number, idgame:int):Number {
  var result:int = Math.round(Math.random() * (max - min)) + min;
  while (result == idgame)
    result = Math.round(Math.random() * (max - min)) + min;
  return result;
}

Добавлено через 3 минуты
Еще вариант:
Код AS3:

public function random(min:Number, max:Number, idgame:int):Number {
  var arr:Array = [];
  for (var i:int = min; i <= max; i++) if (i != idgame) arr.push(i);
  var len = arr.length;
  return arr[int(Math.random() * len)];
}

Добавлено через 13 минут
Ждем более изящных решений :)

Scorp2008 28.01.2012 13:39

Спасибо большое :)

Zolza 29.01.2012 06:44

Код AS3:

public function randomExeption(max:Number, min:Number, exeption:Number):Number
                {
                        var mod:Number = 1;
                        var t:uint = getTimer() % 2;
                        if (!t) return Math.random() * (exeption - min) + min;
                        else return Math.random() * (max - exeption) +(exeption + mod);
                }

Переменная mod для того, чтобы точно не нарваться на исключаемое число. Для целых исключаемых подойдет 1, для вещественных можно и меньше, 0.1 например.

-De- 29.01.2012 07:10

Код AS3:

public function randomNum(min:Number, max:Number, ex:Number):Number {
        var ret:Number = Math.random() * (max - min) + min;
        if(ret == ex)
                ret = max;
        return ret;
}
public function randomInt(min:int, max:int, ex:int):Number {
        var ret:int = int(Math.random() * (max - min) + min);
        if(ret >= ex)
                ++ret;
        return ret;
 
}


TanaTiX 29.01.2012 07:25

-De-, только что наваял такой же вариант. Тольео для 2-го случая поправь возвращаемое значение на int, и в расчетах тоже, там Number не нужен.

fish_r 29.01.2012 07:58

Код AS3:

                function selectNm( max:int, min:int, ex:int ):int
                {
                        var res:int = Math.random() * ( max - min ) + min;
 
                        if ( res === ex ) res = selectNm( max, min, ex );
 
                        return res;
                }


Wolsh 29.01.2012 07:58

-De-, TanaTiX – А что, ситуации когда ex == max исторически исключаются?)

fish_r 29.01.2012 07:59

но самый прикольный напишет 2wvxvw, если конечно заглянет в тему )

TanaTiX 29.01.2012 08:50

Wolsh, тогда необходима либо дополнительная проверка, либо теряется равномерность рэндома (с учетом всех его недостатков во флеше)
fish_r, +1 :)

i.o. 29.01.2012 10:07

С целочисленными без циклов можно так:
Код AS3:

/**
 *  min < max;
 *  min <= excluded
 *  min <= result < max
 */

function randomInt( min:int, max:int, excluded:int ) : int
{
        var r:int = min + (max - min - 1) * Math.random();
        return r + int(r >= excluded);
}
 
 
var matches:Array = new Array();
var i:int = 10000;
while (i--)
{
        var j:int = randomInt(10, 30, 13);
        if (matches[j] === undefined)
                matches[j] = 0;
        else
                matches[j]++;
}
 
for (i=10; i < 30; i++)
{
        trace("[" + i + "]: " + matches[i]);
}

Код:

[10]: 480
[11]: 489
[12]: 521
[13]: undefined
[14]: 513
[15]: 511
[16]: 548
[17]: 525
[18]: 546
[19]: 569
[20]: 523
[21]: 571
[22]: 492
[23]: 550
[24]: 495
[25]: 534
[26]: 544
[27]: 527
[28]: 547
[29]: 496


HardCoder 29.01.2012 10:55

Цитата:

Сообщение от TanaTiX (Сообщение 1059725)
[b]теряется равномерность рэндома (с учетом всех его недостатков во флеше)

А можно подробнее о недостатках?

TanaTiX 29.01.2012 11:24

HardCoder, если погуглить, то можно найти информацию о том, что рэндом во флеше... Скажем так, не на столько случайный, как хотелось бы. Хотя для флеша это практически роли не играет. Я это добавил только справедливости ради.

-De- 29.01.2012 11:50

Wolsh, нет не исключаются. Для них условие по идее никогда не выполнится. Т.к. Math.random() никогда не равен 1 (см. доки). Хотя возможно при каких-то значениях min и max и максимальном Math.random() выражение Math.random() * (max - min) + min будет равно max из-за ошибок округления =)
TanaTiX
опс, перепутал тела функций 0_0

HardCoder 29.01.2012 12:32

Цитата:

Сообщение от TanaTiX (Сообщение 1059736)
HardCoder, если погуглить, то можно найти информацию о том, что рэндом во флеше... Скажем так, не на столько случайный, как хотелось бы.

Я свой вопрос задал, потому что люблю, когда вещи называют своими именами. Очень режет слух слишком смелые высказывания о том, что когда Math.random() выдает не то что хочет видеть человек - называть его "не слишком случайным". Если нужно 10 раз получить случайное число в диапазоне от 0 до 3, рэндом 7 раз может вывести 0, один раз 1, один раз 2 и один раз 3. (цифры от фонаря взял). Вот это случайность - ее невозможно предугадать. А нам нужно, чтоб 0, 1, 2, 3 выпадали с некоей равномерностью. Поэтому нельзя обвинять рэндом в неслучайности, когда нам нужна не случайность, а закономерность. Я когда-то долго искал ОБЪЕКТИВНЫЕ доказательства неслучайности рэндома. И до сих пор не нашел, поэтому и задал вопрос. Согласен - для создания приложений такая абсолютная случайность иногда не подходит, поэтому нужно писать разные алгоритмы, чтобы числа выбрасывались с некоторой равномерностью.

TanaTiX 29.01.2012 12:57

Цитата:

Поэтому нельзя обвинять рэндом в неслучайности, когда нам нужна не случайность, а закономерность.
Спорить не буду, к тому же мне "случайности" рэндома всегда хватало, а такую информацию получил когда-то, бороздя просторы интернета. Есть разные точки зрения на этот счет (в т.ч. аргументированные); как уже говорил, написал эту информацию исключительно ради справедливости, а не для очередного холивара и массовых проверок.

HardCoder 29.01.2012 13:01

Цитата:

Сообщение от TanaTiX (Сообщение 1059747)
как уже говорил, написал эту информацию исключительно ради справедливости, а не для очередного холивара и массовых проверок.

Согласен. Да умрет холивар в этой теме!

Wolsh 29.01.2012 17:10

Цитата:

Wolsh, нет не исключаются. Для них условие по идее никогда не выполнится.
Ага. Поэтому trace(randomInt(0, 5, 6)); никогда не выдаст 5. Ситуация с параметрами может и лукавая, но вполне вероятная на практике.
Еще у этого алгоритма одно из чисел диапазона никогда не выдается в первой десятке результатов, что прискорбно((

Добавлено через 27 минут
Сама идея замены совпадения с исключением на сознательно негенерируемый max весьма элегантна.
Претензия только к тому, что поведение при таких параметрах "удивляет", то есть не соответствует ожидаемому.

silin 29.01.2012 18:02

такой еще вариант до кучи )
Код AS3:

public function random(min:int, max:int, except:int):int
{
 
        if (Math.random() < (except - min) / (max - min))
        {
                return min + int(Math.random() * (except - min));
        }else
        {
                return max - int(Math.random() * (max - except));
        }
}


wvxvw 29.01.2012 19:53

Тут очень много зависит от того, что именно вы называете случайным числом. Фишка в том, что ни один из приведенных выше примеров скорее всего не пройдет diehard test, не смотря на то, что число, вобщем-то будет "случайным".
Вариант о котором я думал: выбирать случайно из двух диапазонов: min<exclude и exclude>max - но это расточительно, если нужно часто радном генерировать.
А можно полюбопытствовать, зачем это понадобилось, и на скольк важна правильная (взвешенная) рандомность?

silin: О, я твой вариант не видел, когда писал, я вот тоже о чем-то таком думал, только не нужно два раза random() вызывать. Если закешировать первый вызов и им и воспользоваться, то и дешевле выйдет и больше вероятность, что в итоге распределение будет правильным.

silin 29.01.2012 20:20

>> выбирать случайно из двух диапазонов: min<exclude и exclude>max - но это расточительно
ровно на один Math.random(), едва ли не дешевле, чем другие выверты

а насчет diehard test, что-то не могу такой задачки для флеша вообразить даже

wvxvw 29.01.2012 20:33

Ну тут не только то, что дешевле, вовсе не факт, что Math.random() * Math.random() дают правильное распределение - надо тестировать.
А по поводу diehard тестов я не понял замечание - это как бы тесты для любого рандома, на чем хочешь пиши - они тестируют распределение. Т.е. есть определенные требования к равномерному распределению, например, проблема дня рождения (если предположить что вероятность того, что любой день в году может быть днем рождения кого-то из участников группы - нужно определенное количество человек для того, чтобы вероятность достигла определенного процента). Ну вот если бы приведенный алгоритм проверили таким тестом и получилось бы что вероятность 50% наступает не в группе из 10 человек, а из 5, то это значило бы, что алгоритм плохой (существуют коллизии) - ну а дальше уже, смотря для чего использовать. Если для игры в покер - то плохо, если выбрать в какой случайный цвет покрасить текст на открытке - то без разницы :)

silin 29.01.2012 20:48

про diehard test понятно, непонятно какое это имеет отношение к сабжу,
Math.random() сам-то проходит? :)
если уровня Math.random() достаточно, то сгодится и то, что наворачивается на его базе, никаких сюрпризов с измением 50%-ной группы вдвое не ожидается, ну во всяком случае в варианте с диапазонами (№19)

wvxvw 30.01.2012 01:46

Нет, нет такой зависимости. мы же не знаем точно какая реализация. Ксор-шифт рандом * ксор-шифт рандом, например, не пройдет. Math.random() заявлен как взвешеный рандом - значит должен, но я не проверял. По тем результатам которыми приходилось пользоваться - вроде прходит. Но нет такой гарантии, что композиция одной функции генерации взвешенного рандома с самой даст опять же взвешенный рандом. Ее по определению не может быть :)

ЗЫ. Там где звездочка имеется в виду не умножение а сложение функций, типа \circ в Латексе.

fish_r 30.01.2012 02:58

Цитата:

Сообщение от silin (Сообщение 1059804)
такой еще вариант до кучи )... /код не цитирую - отобразится криво:)/

А если except === max || except === min работать будет криво, а ещё ряд может быть сдвинут частично в отрицательный диапазон (int ведь). Хотя, я подозреваю, что топикстартера интересуют, на самом деле, числа типа uint, просто он несколько не разборчиво отнесся к выбору типа числа.

А мой способ ни когда не вернет max - косяк )
За то такой удобно использовать когда требуется исключить сразу ряд чисел-исключений:

Код AS3:

 
        function selectNm( min:uint, max:uint, exArr:Array ):uint
        {
            var res:uint = min + Math.random() * ( max + 1 - min );
 
            if (  exArr.indexOf( res ) !== - 1 ) res = selectNm( max, min, exArr );
 
            return res;
        }

:)

TanaTiX 30.01.2012 03:18

fish_r, теоретически такой код может уйти в бесконечную рекурсию. Чем больше разброс, тем вероятность меньше.
И кстати, даже если отбросить рекурсию - считать будет не правильно.

Upd. Да, правильно считает, посмотрел не туда.

fish_r 30.01.2012 06:07

Проверил, вродь правильно считает. Ну, да - не для сложных случаев, для простых задач, коих тоже хватает пойдет ).

Добавлено через 11 минут
Хотя ты прав - потенциальный косячок тут заложен, не стал бы его юзать.

silin 30.01.2012 09:18

Цитата:

Сообщение от fish_r (Сообщение 1059896)
А если except === max || except === min работать будет криво, а ещё ряд может быть сдвинут частично в отрицательный диапазон ..

криво будет если исключение вне диапазона, а для краев и отрицательных нормально, или я чего-то упустил?
Код AS3:

public function Main():void
{
        trace(test(-3));// 0,1660,1706,1649,1651,1652,1682
        trace(test(0));// 1693,1650,1720,0,1611,1633,1693
        trace(test(3));// 1642,1608,1681,1662,1702,1705,0
}
 
private function test(exept:int):Array
{
        var res:Array = [0, 0, 0, 0, 0, 0, 0];
        var n:int = 1e4;
        for (var i:int = 0; i < n; i++)
        {
                res[3 + random( -3, 3, exept)]++;
        }
        return res;
}
 
public function random(min:int, max:int, except:int):int
{
 
        if (Math.random() < (except - min) / (max - min))
        {
                return min + int(Math.random() * (except - min));
        }
        else
        {
                return max - int(Math.random() * (max - except));
        }
}


fish_r 30.01.2012 10:17

Цитата:

Сообщение от silin (Сообщение 1059921)
криво будет если исключение вне диапазона, а для краев и отрицательных нормально, или я чего-то упустил?

Нет, извиняюсь, это я криво прочел.

wvxvw 30.01.2012 16:26

Все равно, зачем 2 раза рандом вызывать?

Код AS3:

public function random(min:int, max:int, except:int):int
{
        var random:Number = Math.random();
 
        if (random < (except - min) / (max - min))
        {
                return min + int(random * (except - min));
        }
        else
        {
                return max - int(random * (max - except));
        }
}

ОК, вопрос снимается :)

in4core 30.01.2012 16:32

fish_r а у массива есть свойство indexOf ? или я что то не так понял...

DaFive 30.01.2012 17:00

http://help.adobe.com/ru_RU/FlashPla...t/3/Array.html

in4core 30.01.2012 17:07

угу вижу. просто никогда не пользовался

silin 30.01.2012 19:16

Цитата:

Сообщение от wvxvw (Сообщение 1060036)
Все равно, зачем 2 раза рандом вызывать?
..
ОК, вопрос снимается :)

а ведь ты прав, можно и с одним
Код AS3:

public function random(min:int, max:int, except:int):int
{
        var random:Number = Math.random();
        var ratio:Number = (except - min) / (max - min);
 
        if (random < ratio )
        {
                return min + int(random / ratio * (except - min));
        }
        else
        {
                return max - int((1 - random) / (1 - ratio) * (max - except));
        }
}


Nooob 30.01.2012 19:43

Тест на скорость и качество рандома, брались целые числа от 0 до 30 включительно, исключалось 5
Код AS3:

random1 ---------
0  =>  333440 0.0333
1  =>  332597 0.0333
2  =>  333305 0.0333
3  =>  332736 0.0333
4  =>  332711 0.0333
6  =>  334101 0.0334
7  =>  333831 0.0334
8  =>  332383 0.0332
9  =>  332962 0.0333
10  =>  332951 0.0333
11  =>  332498 0.0332
12  =>  333338 0.0333
13  =>  333087 0.0333
14  =>  333810 0.0334
15  =>  333477 0.0333
16  =>  333979 0.0334
17  =>  333544 0.0334
18  =>  333990 0.0334
19  =>  333006 0.0333
20  =>  334569 0.0335
21  =>  333063 0.0333
22  =>  332528 0.0333
23  =>  334435 0.0334
24  =>  332408 0.0332
25  =>  333202 0.0333
26  =>  333793 0.0334
27  =>  333052 0.0333
28  =>  334687 0.0335
29  =>  332766 0.0333
30  =>  333751 0.0334
max: 0.0335
min: 0.0332
time 5104
random2 ---------
0  =>  333387 0.0333
1  =>  333269 0.0333
2  =>  334142 0.0334
3  =>  332735 0.0333
4  =>  333304 0.0333
6  =>  334511 0.0335
7  =>  332390 0.0332
8  =>  333775 0.0334
9  =>  333638 0.0334
10  =>  334384 0.0334
11  =>  331774 0.0332
12  =>  333715 0.0334
13  =>  332765 0.0333
14  =>  333892 0.0334
15  =>  332855 0.0333
16  =>  333543 0.0334
17  =>  333384 0.0333
18  =>  333845 0.0334
19  =>  333176 0.0333
20  =>  333791 0.0334
21  =>  333333 0.0333
22  =>  333266 0.0333
23  =>  333152 0.0333
24  =>  333917 0.0334
25  =>  332545 0.0333
26  =>  332034 0.0332
27  =>  332994 0.0333
28  =>  333013 0.0333
29  =>  333907 0.0334
30  =>  333564 0.0334
max: 0.0335
min: 0.0332
time 4653
random3 ---------
0  =>  1667509 0.1668
6  =>  399696 0.04
7  =>  399660 0.04
8  =>  400894 0.0401
9  =>  399009 0.0399
10  =>  399507 0.04
11  =>  399832 0.04
12  =>  399777 0.04
13  =>  399750 0.04
14  =>  399956 0.04
15  =>  399588 0.04
16  =>  401202 0.0401
17  =>  399070 0.0399
18  =>  400281 0.04
19  =>  399702 0.04
20  =>  400266 0.04
21  =>  400008 0.04
22  =>  399781 0.04
23  =>  400112 0.04
24  =>  401127 0.0401
25  =>  399899 0.04
26  =>  333374 0.0333
max: 0.1668
min: 0.0333
time 4233

Код AS3:

function result(method:Function):void
{
        dic = new Dictionary();
        time = getTimer();
 
        for (i = 0; i < maxit; i++)
        {
                n = method(0,30,5);
                dic[n] ||0;
                dic[n]++;
        }
 
        var max:Number = 0;
        var min:Number = 30;
        var k:Number = 0;
 
        for (key in dic)
        {
                k = Math.round(dic[key] / maxit * 10000) / 10000;
                max = Math.max(max,k);
                min = Math.min(min,k);
                trace(key, " => ", dic[key], k);
        }
 
        trace("max:", max);
        trace("min:", min);
        trace("time", getTimer() - time);
}
 
var dic:Dictionary;
var i:int;
var n:int;
var key:String;
var time:uint;
var maxit:int = 10000000;
 
function random1(min:int, max:int, except:int):int
{
        if (Math.random() < (except - min) / (max - min))
        {
                return min + int(Math.random() * (except - min));
        }
        else
        {
                return max - int(Math.random() * (max - except));
        }
}
 
trace("random1 ---------");
result(random1);
 
 
function random2(min:int, max:int, except:int):Number
{
        max++;
        var rand:Number = min + int(Math.random() * (max - min - 1));
        return int(rand + Number(rand >= except));
}
 
trace("random2 ---------");
result(random2);
 
function random3(min:int, max:int, except:int):int
{
        var random:Number = Math.random();
 
        if (random < (except - min) / (max - min))
        {
                return min + int(random * (except - min));
        }
        else
        {
                return max - int(random * (max - except));
        }
}
 
trace("random3 ---------");
result(random3);


silin 30.01.2012 20:12

2й вариант в тесте будет еще быстрее, если его нормально записать
Код AS3:

function random2(min:int, max:int, except:int):int
{
        var rand:int = min + int(Math.random() * (max - min));
        return rand < except ? rand : ++rand;
}

а 3й должен быть в редакции из поста №34, иначе врет, выяснили уже ж

Korben 30.01.2012 22:27

Алгоритм раздачи случайного бонуса и т.п. :)

Я решал этот алгоритм по другому - создавался массив доступных чисел и потом удалялся случайный элемент.
Массив может жить долго с объектом и нет необходимости помнить какие числа надо игнорировать
:)

firuz 30.01.2012 22:29

А можно и рекурсией

Код AS3:

public function RecRand (_min:Number, _max:Number, _ex:Number) : Number {
                        var ran:Number = Math.round(Math.random() * (_max - _min)) + _min;
                        if (ran == _ex) {
                                trace("Выбросить ", ran);
                                return RecRand(_min, _max, _ex);
                        }
 
 
                        var ranNumb:Number = ran;
                        return ranNumb
                }


in4core 30.01.2012 23:53

Цитата:

var ranNumb:Number = ran;
return ranNumb
Апокрефично

firuz 31.01.2012 00:43

Цитата:

Сообщение от in4core (Сообщение 1060147)
Апокрефично

хахаха! я явно задумывал что-то дургое сначала! а потом забыл удалить :)
но ведь работает


Часовой пояс GMT +4, время: 23:44.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.