for those who need sqrt() funtion

Post your scripting questions / solutions here

Moderator: Moderators

Post Reply
SilentAngel
Captain
Posts: 239
Joined: Wed Mar 12, 2008 8:27 pm

for those who need sqrt() funtion

Post by SilentAngel »

this is basically the best way I found to return sqrt of a a value..

Code: Select all


//*****************************************************************//
//*This method is used to calculate a fast approximate square root*//
//*****************************************************************//
sqrt local.arg:

	if(local.arg == 1)
		end 1

	local.Xn = float(1)
	
	for(local.i = 1; local.i <= 100; local.i++)
	{
		local.v1 = float(local.Xn) / float(2)
		local.v2 = float(local.arg) / ( float(2) * float(local.Xn) )
		local.Xn = local.v1 + local.v2
	}
	
	local.return = local.Xn
	
end local.return

considering that MOH float display only 3 decimals that's pretty accurate..however remember that the more we want it accurate the more we have to increase the number of cycles in the for statement..also if you use really really big numbers ( 1040870 for exemple :) ) you need more cycles inside for..for exemple you can switch from 100 to 1000..
jv_map
Site Admin
Posts: 6521
Joined: Tue Sep 03, 2002 2:53 pm
Location: The Netherlands
Contact:

Post by jv_map »

Nice :)

I once wrote this sqrt implementation:

Code: Select all

// fast square-root
// only usuable near x=1
// McLaurin expansion
sqrt1 local.x:
end (1.0 + 0.5 * (local.x - 1.0) - 0.125 * (local.x - 1.0) * (local.x - 1.0))

// square-root
// more accurate than pow^.5
sqrt local.x:
	// sqrt(2)
	local.SQRT_2 = 1.4142135623730951

	// known values, how convenient
	if(local.x == 0.0)
	{
		local.result = 0.0
	}
	else if(local.x == 1.0)
	{
		local.result = 1.0
	}
	else if(local.x == 2.0)
	{
		local.result = local.SQRT_2
	}
	else if (local.x < 0.0)
	{
		// error
		println "ERROR[math::sqrt]: sqrt(" local.x ") has no real solution"
		local.result = 0.0
	}
	else
	{
		// reduce x to [1,2] domain
		local.wx = local.x
		local.steps = 0
		local.dividesteps = 0
		
		// reduce below 2.0
		while (local.wx > 2.0)
		{
			local.wx = 0.5 * local.wx
			local.steps++
		}
		
		// increase above 1.0
		while(local.wx < 1.0)
		{
			local.wx = 2.0 * local.wx
			local.dividesteps++
		}
		
		// evaluate in [1,2] domain
		if(local.wx == 1.0)
		{
			local.eval = 1.0
		}
		else if (local.wx == 2.0)
		{
			local.eval = local.SQRT_2
		}
		else
		{
			// approximation
			local.EVALSLOPE = 0.4267766953
			local.EVALMOD = 1.224744871 - 1.51 * local.EVALSLOPE
			local.eval = local.EVALSLOPE * local.wx + local.EVALMOD
		}
		
		// multiply back to original domain
		for(local.i = 1; local.i <= local.steps; local.i++)
		{
			local.eval = local.eval * local.SQRT_2
		}
		
		// divide back to original domain
		for(local.i = 1; local.i <= local.dividesteps; local.i++)
		{
			local.eval = local.eval / local.SQRT_2
		}
	
		// correct until required accuracy has been reached
		local.MAXREFINEMENTSTEPS = 2;

		for(local.i = 1; local.i <= local.MAXREFINEMENTSTEPS; local.i++)
		{
			local.fact = local.eval * local.eval / local.x
			local.eval = local.eval / (waitthread sqrt1 local.fact)
		}
		
		local.result = local.eval
	}
end local.result
It scales the input to the domain [1,2] to keep the cost under control with constant relative error on the entire domain. :)
Image
SilentAngel
Captain
Posts: 239
Joined: Wed Mar 12, 2008 8:27 pm

Post by SilentAngel »

yep good work! :wink:
but why didn't they implemented sqrt function in scripting language? Maybe they preferred let us have fun scripting these all! :D
Post Reply