Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 1.0/2.0 (http://www.flasher.ru/forum/forumdisplay.php?f=93)
-   -   Как random поменять на Math.random() (http://www.flasher.ru/forum/showthread.php?t=137157)

Wadimir 05.03.2010 20:07

Как random поменять на Math.random()
 
Добрый день!

Как random в этом коде
Код AS1/AS2:

onEnterFrame = function () {
        t = random(2);
        if (t == 1) {
                a._x = 400;
        } else {
                a._x = 200;
        }
};

Поменять на Math.random() и чтобы смысл оставался тот же

Hauts 05.03.2010 21:08

Код AS1/AS2:

a._x = 200+200*Math.round(Math.random())


Wadimir 05.03.2010 23:15

А если значений больше:
Код AS1/AS2:

t = random(5);
        if (t == 1) {
                a._x = 453;
        } 
        if (t == 2) {
                a._x = 590;
        }
        if (t == 3) {
                a._x = 400;
        }
        if (t == 4) {
                a._x = 650;
        }
        if (t == 5) {
                a._x = 350;
        }

тогда как?

gloomyBrain 05.03.2010 23:26

Код AS1/AS2:

var maxValue:Number = 100; // от 0 до 100
switch(Math.floor(Math.random()*maxValue + 1)) {
 
case 1:
t = 1;
break;
 
case 2:
t = 32;
break;
 
// и так далее по образу и подобию
}


AzagThoth 06.03.2010 02:09

to gloomyBrain
Страшно даже)) Зачем столько строк писать когда одной можно.
Код AS1/AS2:

t = Math.round(Math.random*VALUE);//где VALUE максимальное значение

Ну а дальше ставите Ваш код с ифами.

udaaff 06.03.2010 02:15

Код AS1/AS2:

var array:Array = [ 453, 590, 400, 650, 350 ];
a._x = array[Math.floor(Math.random() * 5];


Wadimir 06.03.2010 19:16

спасибо, буду пробовать

etc 07.03.2010 22:24

Только не round, а floor.

AzagThoth 08.03.2010 13:06

А чем Вам round не нравится?
Код AS1/AS2:

Math.round()
Доступность
Flash Player 5. Во Flash Player 4 методы и свойства класса Math эмулируются при помощи приближенных вычислений и могут быть не так точны, как во Flash Player 5 и более поздних.
 
Синтаксис
Math.round(x:Number) : Number
 
Параметры
x A number.
 
Возвращает
Целое число.
 
Описание
Метод; округляет значение x по правилам математики. Если x одинаково близок к двум целым числам (то есть, оканчивается .5), округление происходит в большую сторону.


udaaff 08.03.2010 13:28

Цитата:

Сообщение от AzagThoth (Сообщение 891668)
А чем Вам round не нравится?

Вероятность неверно распределится.


upd: обнаружил такую вещь:

Код AS1/AS2:

var a:Array = [ 0, 0, 0, 0, 0 ];
var b:Array = [ 0, 0, 0, 0, 0 ];
 
for (var i:Number = 0; i < 100; i++)
{
        var k:Number = Math.round(Math.random() * 4);
        b[k]++;
        a[Math.round(Math.random() * 4)]++;
}
 
var sumA:Number = 0;
var sumB:Number = 0;
 
for (i = 0; i < 5; i++)
{
        sumA += a[i];
        sumB += b[i];
}
trace("sumA " + sumA + " sumB " + sumB);

При настройках публикации AS2 FP9 trace() выдает:
sumA 128 sumB 100
sumA 116 sumB 100
sumA 117 sumB 100
Т.е. выражение a[Math.round(Math.random() * 4)]++; работает непонятным мне образом.

При настройках публикации AS3 и там и там 100, как и предполагалось.

Это какой-то баг о котором я не знал? В курсе кто-нибудь?

etc 08.03.2010 14:11

Цитата:

Сообщение от AzagThoth (Сообщение 891668)
А чем Вам round не нравится?

Тем, что пределы могут не совпадать с обычным random(). В частности, может достигать верхнего.

wvxvw 08.03.2010 16:26

В принципе - баг, надо искать Флазм и смотреть почему так происходит. На сколько я знаю, флеш никогда не использовал unsafe pointers, так что причина скорее всего в вом, что оно где-то число принимает за строку... кстати, надо еще MTASCом попробовать скомпилить и посмотреть, что будет.

Хмм... MTASC такой же результат выдает, значит, скорее всего бага плеера...

udaaff 08.03.2010 17:15

wvxvw, спасибо за ответ.
Хоть и не понятно в чем конкретно баг заключается, но теперь буду осторожней с такими выражениями обращаться.

wvxvw 08.03.2010 19:22

Кстати, врезультате тестов появилось следующее:
Код AS1/AS2:

/**
 * ...
 * @author wvxvw
 */

class org.wvxvw.Type
{
        private var _name:String;
        private var _value:Function;
        private static var _tpyeHash:Object = { };
 
        private function Type(value:Function)
        {
                super();
                if (!value) throw new Error("Cannot resolve type");
                var package:String;
                var nameChain:Array/*String*/;
                _global.ASSetPropFlags(_global, null, 6, true);
                for (var p:String in _global)
                {
                        if (_global[p] === value)
                        {
                                this._name = p;
                        }
                        if (!(_global[p] instanceof Object)) continue;
                        nameChain = this.findRefRecursive(_global[p], [p], value);
                        if (nameChain) break;
                }
                if (!this._name)
                {
                        if (!nameChain)
                        {
                                throw new Error("Cannot resolve type");
                        }
                        else
                        {
                                this._name = String(nameChain.pop());
                                package = nameChain.join(".");
                                this._name = package + "::" + this._name;
                        }
                }
                this._value = value;
        }
 
        public static function resolveType(value:Function):Type
        {
                for (var p:String in _tpyeHash)
                {
                        trace(_tpyeHash[p]);
                        if (Type(_tpyeHash[p]).valueOf() == Object(value))
                                return Type(_tpyeHash[p]);
                }
                var t:Type;
                t = new Type(value);
                _tpyeHash[t.toString()] = t;
                return t;
        }
 
        public function is(value:Object):Boolean
        {
                switch (this._value)
                {
                        case Boolean:
                                return typeof value == "boolean";
                        case String:
                                return typeof value == "string";
                        case Number:
                                return typeof value == "number";
                }
                return Boolean(this._value(value));
        }
 
        public function valueOf():Object { return this._value; }
 
        private function findRefRecursive(where:Object/*Object*/,
                                                                        nameChain:Array/*String*/,
                                                                        meth:Function):Array/*String*/
        {
                var o:Object;
                var nextSibling:Array/*String*/;
                for (var p:String in where)
                {
                        o = where[p];
                        if (o === meth)
                        {
                                nameChain.push(p);
                                return nameChain;
                        }
                        else if (o instanceof Object && !(o instanceof Function))
                        {
                                nextSibling = this.findRefRecursive(o, nameChain.concat([p]), meth);
                                if (nextSibling) return nextSibling;
                        }
                }
                return null;
        }
 
        public function toString():String { return this._name; }
}

Код AS1/AS2:

import org.wvxvw.Type;
 
/**
 * ...
 * @author wvxvw
 */

class org.wvxvw.ArrayList
{
        public function get type():Type { return this._type; }
 
        public function get array():Array { return this._array.concat(); }
 
        private var _type:Type;
        private var _array:Array/*T*/;
 
        public function ArrayList(type:Type)/*T*/
        {
                super();
                this._type = type;
                this._array = [];
        }
 
        public function push(param:Object/*Null<T>*/):Number
        {
                if (param === null || this._type.is(param))
                        return this._array.push(param);
                throw new Error(param + " is not a a valid type.");
                return NaN;
        }
 
        public function unshift(param:Object/*Null<T>*/):Number
        {
                if (param === null || this._type.is(param))
                        return this._array.unshift(param);
                throw new Error(param + " is not a a valid type.");
                return NaN;
        }
 
        public function pop():Object/*Null<T>*/
        {
                return this._array.pop();
        }
 
        public function shift():Object/*Null<T>*/
        {
                return this._array.shift();
        }
 
        public function splice(where:Number, items:Number,
                                        replaceWith:ArrayList/*T*/):ArrayList/*T*/
        {
                if (replaceWith && replaceWith.type !== this._type)
                        throw new Error("Type mismatch");
                var arr:ArrayList/*T*/ = new ArrayList(this._type)/*T*/;
                var clone:Array;
                var cloneHead:Array = this._array.slice(0, where);
                var cloneTail:Array = this._array.slice(where + items, this._array.length);
                var insert:Array
                if (replaceWith)
                {
                        insert = replaceWith.array;
                        clone = cloneHead.concat(insert.concat(cloneTail));
                }
                else clone = cloneHead.concat(cloneTail);
                ArrayList/*T*/.setSource(arr, clone);
                return arr;
        }
 
        public function slice(from:Number, to:Number):ArrayList/*T*/
        {
                var arr:Array = this._array.splice(from, to);
                var arrList:ArrayList = new ArrayList(this._type)/*T*/;
                ArrayList/*T*/.setSource(arrList, arr);
                return arrList;
        }
 
        public function toString():String
        {
                return "ArrayList<" + this._type + ">[" + this._array.join(", ") + "]";
        }
 
        private static function setSource(to:ArrayList/*T*/, source:Array/*T*/):Void
        {
                to._array = source;
        }
}

Нечем было заняться :)

Самое интересное то, что если вычитать а не складывать, то результат опять же будет неправильным... и если последовательно трейсить trace(a) в первом цикле, то видно, что иногда массив не изменяется... вобщем, скорее всего какай-нибудь пропущенная команда в сгенерированом коде, либо плеер неправильно читает команду (забывает при каких-то обстоятельствах)...

etc 08.03.2010 23:03

Цитата:

Сообщение от wvxvw (Сообщение 891740)
Код AS1/AS2:

private static var _tpyeHash:Object = { };


Жертва опечатки.

wvxvw 09.03.2010 03:41

Онa все равно приватная :p

На самом деле самое глупое в этом - это ошибки кидать / ловить в AS2. В большинстве случаев плеер их сам отрабатывает и не дает до них добраться... :( т.е. если функция вернулась с ошибкой а ее вызвала другая функция, то в третей функции, которая вызвала вторую про ошибку уже все забыли, просто где-то undefined будет... Страшно подумать, что на этом когда-то что-то всерьез писалось...

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

Psycho Tiger 09.03.2010 12:05

Код AS3:

for (var i:Number = 0; i < 100; i++)
{
        var k:Number = Math.round(Math.random() * 4);
        b[k]++;
        a[Math.round(Math.random() * 4)]++;
}

Я не понимаю, почему k обязанно за 100 итераций выпасти 20 раз? Ровно как и Math.round(Math.random() * 4).

udaaff 09.03.2010 12:10

Цитата:

Я не понимаю, почему k обязанно за 100 итераций выпасти 20 раз? Ровно как и Math.round(Math.random() * 4).
В смысле?
k выпадает каждую итерацию. И в сумме должно получиться 100 по идее.

wvxvw 09.03.2010 12:56

Код:

movie 'loop.swf' // flash 9, total frames: 1, frame rate: 12 fps, 550x400 px


  frame 0
    constants 'a', 'b', 'i', 'k', 'Math', 'random', 'round', 'sumA', 'sumB', 'sumA ', ' sumB ' 
    push 'a', 0.0, 0.0, 0.0, 0.0, 0.0, 5
    initArray
    varEquals
    push 'b', 0.0, 0.0, 0.0, 0.0, 0.0, 5
    initArray
    varEquals
    push 'i', 0.0
    varEquals
  label1:
    push 'i'
    getVariable
    push 100
    lessThan
    not
    branchIfTrue label2
    push 'k', 0.0, 'Math'
    getVariable
    push 'random'
    callMethod
    push 4
    multiply
    push 1, 'Math'
    getVariable
    push 'round'
    callMethod
    varEquals
    push 'b'
    getVariable
    push 'k'
    getVariable
    push 'b'
    getVariable
    push 'k'
    getVariable
    getMember
    increment
    setMember

    push 'a'
    getVariable
    push 0.0, 'Math'
    getVariable
    push 'random'
    callMethod
    push 4
    multiply
    push 1, 'Math'
    getVariable
    push 'round'
    callMethod
    push 'a'
    getVariable
    push 0.0, 'Math'
    getVariable
    push 'random'
    callMethod
    push 4
    multiply
    push 1, 'Math'
    getVariable
    push 'round'
    callMethod
    getMember
    increment
    setMember

    push 'i', 'i'
    getVariable
    increment
    setVariable
    branch label1
  label2:
    push 'sumA', 0.0
    varEquals
    push 'sumB', 0.0
    varEquals
    push 'i', 0.0
    setVariable
  label3:
    push 'i'
    getVariable
    push 5
    lessThan
    not
    branchIfTrue label4
    push 'sumA', 'sumA'
    getVariable
    push 'a'
    getVariable
    push 'i'
    getVariable
    getMember
    add
    setVariable
    push 'sumB', 'sumB'
    getVariable
    push 'b'
    getVariable
    push 'i'
    getVariable
    getMember
    add
    setVariable
    push 'i', 'i'
    getVariable
    increment
    setVariable
    branch label3
  label4:
    push 'sumA ', 'sumA'
    getVariable
    add
    push ' sumB '
    add
    push 'sumB'
    getVariable
    add
    trace
  end // of frame 0
end

Это вот что получается после компиляции - ну, давайте попробуем разобраться :)

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

iNils 09.03.2010 13:34

Собственно все и так ясно.
Выражение
Код AS1/AS2:

а[Math.round(Math.random() * 4)]++

это тоже самое, что и
Код AS1/AS2:

а[Math.round(Math.random() * 4)] = а[Math.round(Math.random() * 4)] + 1

Из этого видно, что индексы в правой и левой части будет в основном отличаться (вызов будет два раза), что и приводит к тому, что сумма не равна 100.
С b все ясно, так как "k" в выражении
Код AS1/AS2:

b[k] = b[k] + 1

будет совпадать для обоих частей

В avm2 переписали инкремент, поэтому левая часть для a берется из правой части.

Psycho Tiger 09.03.2010 14:31

Очень интересно :)
То есть в avm2 вызов Math.random() будет один - но как то нелогично, что берет из правой части, наверное, логичней было бы брать с левой?
2udafff: точно, голова кипит :)

iNils 09.03.2010 14:47

Ну, это мое предположение, что переписали, а не факт. :)
Просто проверить легко, вместо рнд впихнуть в массив вызов функции, где рнд и будет формироваться, потом в трейс и на выход в return.
В avm1 два трейса, в avm2 - один.

wvxvw 09.03.2010 15:02

Цитата:

Сообщение от iNils (Сообщение 891858)
Собственно все и так ясно.
Выражение
Код AS1/AS2:

а[Math.round(Math.random() * 4)]++

это тоже самое, что и
Код AS1/AS2:

а[Math.round(Math.random() * 4)] = а[Math.round(Math.random() * 4)] + 1

Из этого видно, что индексы в правой и левой части будет в основном отличаться (вызов будет два раза), что и приводит к тому, что сумма не равна 100.
С b все ясно, так как "k" в выражении
Код AS1/AS2:

b[k] = b[k] + 1

будет совпадать для обоих частей

В avm2 переписали инкремент, поэтому левая часть для a берется из правой части.

Неа.
Посмотри на дамп:
- вызов Math.random() во втором случае только 1 раз.
- даже если бы он вызывался 2 раза - какая разница какой из элементов массива инкрементить? Судя по всему почему-то, в какой-то ситуации значение из стека не присваевается обратно элементу в массиве.

EDIT: Ой, сорри - был не прав, проморгал, действительно Math.random() вызывается 2 раза... :( Чет я проглядел

AzagThoth 09.03.2010 16:12

А кто может на примере объяснить почему Math.floor()
Код AS1/AS2:

Math.floor()
Доступность
Flash Player 5. Во Flash Player 4 методы и свойства класса Math эмулируются при помощи приближенных вычислений и могут быть не так точны, как во Flash Player 5 и более поздних.
 
Синтаксис
Math.floor(x:Number) : Number
 
Параметры
x Число или выражение
 
Возвращает
Округленное в меньшую сторону число x.
 
Описание
Метод; находит ближайшее к и одновременно меньшее числа x число и возвращает его.
 
Пример
Данный код вернет значение 12:
 
Math.floor(12.5);
 
Данный код вернет значение -7:
 
Math.floor(-6.5);

лучше пременять чем Math.round()
Код AS1/AS2:

Math.round()
Доступность
Flash Player 5. Во Flash Player 4 методы и свойства класса Math эмулируются при помощи приближенных вычислений и могут быть не так точны, как во Flash Player 5 и более поздних.
 
Синтаксис
Math.round(x:Number) : Number
 
Параметры
x A number.
 
Возвращает
Целое число.
 
Описание
Метод; округляет значение x по правилам математики. Если x одинаково близок к двум целым числам (то есть, оканчивается .5), округление происходит в большую сторону.
 
Пример
В следующем примере возвращается случайное число в указанном диапазоне.
 
function randRange(min:Number, max:Number):Number {
  var randomNum:Number = Math.round(Math.random()*(max-min))+min;
  return randomNum;
}
for (var i = 0; i<25; i++) {
  trace(randRange(4, 11));
}

Ибо лично я, никак не догоняю.
Цитата:

Сообщение от etc (Сообщение 891676)
Тем, что пределы могут не совпадать с обычным random(). В частности, может достигать верхнего.

Цитата:

Сообщение от udaaff (Сообщение 891671)
Вероятность неверно распределится.

Что значит не совпадать и не верно? А как верно тогда? По моему из описания ясно видно что в одном случае когда 0.5 округление в 1, а в другом в 0. И где же тут неверность? В общем ничего не понятно. По моему эти 2 варианта совершенно равнозначны. И если мы округляем то разумеется логичнее округлять по правилам математики, а это как раз Math.round().

etc 09.03.2010 17:49

AzagThoth, если вы пишете аналог random() с использованием Math.random(), то вам нужно знать, что random() возвращает целое число от 0 до N, не включая N.

iNils 09.03.2010 18:01

Эти два варианта
Код AS1/AS2:

Math.floor (Math.random () * 5)
Math.round (Math.random () * 5)

дают на выходе разный диапазон чисел, floor 0..4, а round 0..5. Поэтому, когда вы генерите числа для доступа к массиву с длиной 5 (0,1,2,3,4), floor укладывается в этот диапазон, а round дает на единицу больше.

Ежели использовать для round множитель не длины, а номер индекса, то вас ждет разочарование - равномерного распределения не будет.
Пример
Код AS3:

var a:Array = [0, 0, 0, 0, 0];
var b:Array = [0, 0, 0, 0, 0];
for (var i:int = 0; i < 1000000; i++) {
        var m:int = Math.floor(Math.random()*5);
        var n:int = Math.round(Math.random()*4);       
        a[m]++
        b[n]++
}
trace (a)
trace (b)

Цитата:

200101,199366,200426,199833,200274
125332,250083,249493,250159,124933
Как видите, с floor идет равномерно распределение, стремящиеся к 1 / 5 от общего числа повторов.
А с round распределения идут в таком соотношение: 1/8, 1/4, 1/4, 1/4, 1/8.
Почему? Да потому, что целое число X (0<X<4) будет получаться от не целых чисел X-0,5..X+0,5 (диапазон равен 1), а числа 0 и 4, от 0..0,5 и 3,5..4 (диапазон равен 0,5), поэтому вероятность для чисел 1,2,3 будет в два раза больше, чем для 0 и 4.

AzagThoth 09.03.2010 18:16

Всё, понял. Большое спасибо! Очень наглядно.


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

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