Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Сообщения за день
 

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 05.06.2011, 18:18
wvxvw вне форума Посмотреть профиль Отправить личное сообщение для wvxvw Найти все сообщения от wvxvw
  № 1  
Ответить с цитированием
wvxvw
Modus ponens
 
Аватар для wvxvw

модератор форума
Регистрация: Jul 2006
Адрес: #1=(list #1#)
Сообщений: 8,049
Записей в блоге: 38
По умолчанию Монте Карло метод + странная ошибка при рассчете Пи

Вот, хотел сделать для детишек демонстацию рассчета Пи по методу Монте Карло, и тут облом Не могу понять почему ошибка, при чем постоянно площадь круга получается больше чем нужно. Код вроде простой, ничего такого заумного...
Код AS3:
package tests
{
	import flash.display.BitmapData;
	import flash.display.BitmapDataChannel;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFormat;
 
	[SWF(width="255", height="275")]
 
	public class MonteCarloIllustration extends Sprite
	{
		private static const RADIUS:uint = 0xFF;
		private const _monitor:TextField = new TextField();
		private const _data:BitmapData = new BitmapData(RADIUS, RADIUS, false, 0);
		private const _noise:BitmapData = new BitmapData(RADIUS, RADIUS, false, 0);
		private const _zeroPoint:Point = new Point();
 
		private var _lastCalculated:Number = 0;
		private var _knownMax:Number = 0;
		private var _knownMin:Number = Number.MAX_VALUE;
 
		public function MonteCarloIllustration()
		{
			super();
			if (super.stage) this.init();
			else super.addEventListener(Event.ADDED_TO_STAGE, this.init);
		}
 
		private function init(event:Event = null):void
		{
			super.removeEventListener(Event.ADDED_TO_STAGE, this.init);
			super.stage.scaleMode = StageScaleMode.NO_SCALE;
			super.stage.align = StageAlign.TOP_LEFT;
			this.prepare();
			super.addEventListener(Event.ENTER_FRAME, this.enterFrameHandler);
		}
 
		private function enterFrameHandler(event:Event):void
		{
			var pi:Number = this.calculate();
			this._monitor.text = "Pi: " + pi;
			this.addNoise();
			this._lastCalculated = pi;
		}
 
		private function prepare():void
		{
			this._monitor.width = this._monitor.y = RADIUS;
			this._monitor.height = 20;
			this._monitor.defaultTextFormat = new TextFormat("_sans");
			this.paint();
			super.addChild(this._monitor);
		}
 
		private function paint():void
		{
			var canvas:Graphics = super.graphics;
			canvas.beginBitmapFill(this._data);
			canvas.drawRect(0, 0, RADIUS, RADIUS);
			canvas.endFill();
		}
 
		private function addNoise():void
		{
			this._noise.noise(Math.random() * int.MAX_VALUE, 
				0, 0xFF, BitmapDataChannel.BLUE);
			this._data.merge(this._noise, 
				this._data.rect, this._zeroPoint, 0, 0, 0xFF, 0);
		}
 
		private function calculate():Number
		{
			var pixels:Vector.<uint> = this._data.getVector(this._data.rect);
			var squareAvg:uint;
			var circleAvg:uint;
			var pixel:uint;
			var blue:uint;
			var result:Number;
 
			for (var total:uint = pixels.length - 1; total > 0; total--)
			{
				pixel = pixels[total];
				// Blue is the channel we use to store the distribution data
				blue = 0xFF & pixel;
				if (isInCircle(total % RADIUS, total / RADIUS))
				{
					// Let's paint those within the circle red.
					circleAvg += blue;
					// In order to visually control that the poins are indeed within
					// the circle, let's paint them red.
					pixels[total] = 0xFF0000 | blue;
				}
				squareAvg += blue;
			}
			this._data.setVector(this._data.rect, pixels);
			result = 4 * circleAvg / squareAvg;
			if (this._knownMax)
			{
				// This is a very naive way to calculate the average :)
				// You may want to improve here
				this._knownMax = Math.max(this._knownMax, result);
				this._knownMin = Math.min(this._knownMin, result);
				result = (this._knownMax + this._knownMin + this._lastCalculated) / 3;
			}
			else this._knownMax = result;
			return result;
		}
 
		private function isInCircle(xPos:uint, yPos:uint):Boolean
		{
			// Simple Pithagor theorem: the sum of powers of two of
			// catheti of the rectangular triangle equals to the power of two
			// of it's hypotenuse. Hence, if the sum of the square of 
			// the catheti is smaller or equal to the radius, the point is within
			// the circle.
			return (xPos * xPos + yPos * yPos) <= RADIUS * RADIUS;
		}
	}
}
EDIT: А, блин, сам спросил и тут же дошло. Рассчитываю-то правильно, только количество пикселов в битмапдате ограничено... И соотношение площади реально нарисованого в ней круга с общей площадью будет не таким, как у "идеального" круга и прямоугольника вокруг него. Хех, прийдется делать приближение по пикселу за итерацию, тогда хоть примерно эффект будет понятен
__________________
Hell is the possibility of sanity


Последний раз редактировалось wvxvw; 05.06.2011 в 18:31.
Старый 05.06.2011, 18:48
alatar вне форума Посмотреть профиль Отправить личное сообщение для alatar Найти все сообщения от alatar
  № 2  
Ответить с цитированием
alatar
 
Аватар для alatar

блогер
Регистрация: Dec 2008
Адрес: Israel, Natanya
Сообщений: 4,740
Записей в блоге: 11
Можно просто радиус увеличить, хотя бы в два раза. Сразу станет ближе к истине.
__________________
משיח לא בא
משיח גם לא מטלפן

Старый 05.06.2011, 19:54
wvxvw вне форума Посмотреть профиль Отправить личное сообщение для wvxvw Найти все сообщения от wvxvw
  № 3  
Ответить с цитированием
wvxvw
Modus ponens
 
Аватар для wvxvw

модератор форума
Регистрация: Jul 2006
Адрес: #1=(list #1#)
Сообщений: 8,049
Записей в блоге: 38
Ну фишка-то в том, что нужно было продемонстритовать, как с помощью этого метода затрачивая меньше усилий можно прощитать сложную формулу, а получилось практически наоборот Вобщем, детерминизм рулит, по-прежнему
__________________
Hell is the possibility of sanity

Старый 05.06.2011, 20:25
i.o. вне форума Посмотреть профиль Отправить личное сообщение для i.o. Найти все сообщения от i.o.
  № 4  
Ответить с цитированием
i.o.
 
Аватар для i.o.

Регистрация: Apr 2010
Адрес: Earth
Сообщений: 1,897
wvxvw, а зачем ты через целочисленные значения пытаешься вычислить Пи?
Почему не напрямую использовать Math.random() вместо шума [0..255]?

Добавлено через 1 час 18 минут
Код AS3:
package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.text.TextField;
 
	public class Main extends Sprite 
	{
 
		public function Main():void 
		{
			this.computePI( 1E+06, 1E+07 );
		}
 
 
		///
		private var _txtLog : TextField;
 
 
		///
		public function computePI( radius:Number, iterations:Number=10 ) : void
		{
			var radiusPow2:Number = radius * radius;
			var hits:Number = 0;
			var i:Number = -1;
			while (++i < iterations)
			{
				var rndX:Number = 2.0 * radius * (0.5 - Math.random());
				var rndY:Number = 2.0 * radius * (0.5 - Math.random());
 
				if (rndX * rndX + rndY * rndY <= radiusPow2)
					hits += 1.0;
			}
 
			var rectS:Number = 4.0 * radiusPow2;
			var circS:Number = rectS * hits / iterations;
			var PI:Number = circS / radiusPow2;
 
			this.addLog("PI: " + PI);
			this.addLog("rectS: " + rectS);
			this.addLog("circS: " + circS);
			this.addLog("iterations: " + iterations);
			this.addLog("hits: " + hits);
		}
 
		///
		public function addLog( msg:String ) : void
		{
			if (!this._txtLog)
			{
				this._txtLog = new TextField();
				this._txtLog.x = 10.0;
				this._txtLog.y = 10.0;
				this._txtLog.width = 400.0;
				this._txtLog.height = 300.0;
				this.addChild( this._txtLog );	
			}
 
			this._txtLog.appendText( msg + "\n" );
		}
 
	}
}
Цитата:
PI: 3.1416376
rectS: 4000000000000
circS: 3141637600000
iterations: 10000000
hits: 7854094
как вариант

Старый 05.06.2011, 22:33
wvxvw вне форума Посмотреть профиль Отправить личное сообщение для wvxvw Найти все сообщения от wvxvw
  № 5  
Ответить с цитированием
wvxvw
Modus ponens
 
Аватар для wvxvw

модератор форума
Регистрация: Jul 2006
Адрес: #1=(list #1#)
Сообщений: 8,049
Записей в блоге: 38
Потому что эффект тот же, точности хватит ровно на столько, на сколько ее может хватить используя конкретный численный тип и радиус. А целочисленный потому что в битмапдате точнее не будет, а хотелось чтобы с картинкой. Собственно, ради картинки и делалось. Т.е. от того, что используя число с плавающей запятой мы получим на 2-3 знака после запятой больше, с точки зрения вероятно бесконечного количества знаков после запятой разница мизерная
Но за пример спасибо. Я кстати перед этим на лиспе сваял, и там можно было с 128-bit float, но, опять же
__________________
Hell is the possibility of sanity

Создать новую тему Ответ Часовой пояс GMT +4, время: 09:32.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


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


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