Форум 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.
Создать новую тему   Часовой пояс GMT +4, время: 11:57.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

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

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


 


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


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