Elminate loadstring. Do parsing manually in complex.to.

String syntax has changed slightly.
Suggested by Satheesh.
master
David Manura 2011-12-13 21:55:08 +05:30
parent 58790b6b7c
commit 8dd7aa293f
3 changed files with 83 additions and 62 deletions

View File

@ -1,5 +1,9 @@
complex changelog
v 0.3.3: 2011-12-13
- Elminate loadstring. Do parsing manually in complex.to.
String syntax has changed slightly.
v 0.3.2: 2011-12-03
- Add _VERSION

View File

@ -59,16 +59,61 @@ DOWNLOAD/INSTALL
--/////////////--
-- link to complex table
local complex = {_TYPE='module', _NAME='complex', _VERSION='0.3.2.20111203'}
local complex = {_TYPE='module', _NAME='complex', _VERSION='0.3.3.20111212'}
-- link to complex metatable
local complex_meta = {}
-- helper functions for parsing complex number strings.
local function parse_scalar(s, pos0)
local x, n, pos = s:match('^([+-]?[%d%.]+)(.?)()', pos0)
if not x then return end
if n == 'e' or n == 'E' then
local x2, n2, pos2 = s:match('^([+-]?%d+)(.?)()', pos)
if not x2 then error 'number format error' end
x = tonumber(x..n..x2)
if not x then error 'number format error' end
return x, n2, pos2
else
x = tonumber(x)
if not x then error 'number format error' end
return x, n, pos
end
end
local function parse_component(s, pos0)
local x, n, pos = parse_scalar(s, pos0)
if not x then
local x2, n2, pos2 = s:match('^([+-]?)(i)()$', pos0)
if not x2 then error 'number format error' end
return (x2=='-' and -1 or 1), n2, pos2
end
if n == '/' then
local x2, n2, pos2 = parse_scalar(s, pos)
x = x / x2
return x, n2, pos2
end
return x, n, pos
end
local function parse_complex(s)
local x, n, pos = parse_component(s, 1)
if n == '+' or n == '-' then
local x2, n2, pos2 = parse_component(s, pos)
if n2 ~= 'i' or pos2 ~= #s+1 then error 'number format error' end
if n == '-' then x2 = - x2 end
return x, x2
elseif n == '' then
return x, 0
elseif n == 'i' then
if pos ~= #s+1 then error 'number format error' end
return 0, x
else
error 'number format error'
end
end
-- complex.to( arg )
-- return a complex number on success
-- return nil on failure
local _retone = function() return 1 end
local _retminusone = function() return -1 end
function complex.to( num )
-- check for table type
if type( num ) == "table" then
@ -88,55 +133,8 @@ function complex.to( num )
return setmetatable( { isnum,0 }, complex_meta )
end
if type( num ) == "string" then
-- check for real and complex
-- number chars [%-%+%*%^%d%./Ee]
local real,sign,imag = string.match( num, "^([%-%+%*%^%d%./Ee]*%d)([%+%-])([%-%+%*%^%d%./Ee]*)i$" )
if real then
if string.lower(string.sub(real,1,1)) == "e"
or string.lower(string.sub(imag,1,1)) == "e" then
return
end
if imag == "" then
if sign == "+" then
imag = _retone
else
imag = _retminusone
end
elseif sign == "+" then
imag = loadstring("return tonumber("..imag..")")
else
imag = loadstring("return tonumber("..sign..imag..")")
end
real = loadstring("return tonumber("..real..")")
if real and imag then
return setmetatable( { real(),imag() }, complex_meta )
end
return
end
-- check for complex
local imag = string.match( num,"^([%-%+%*%^%d%./Ee]*)i$" )
if imag then
if imag == "" then
return setmetatable( { 0,1 }, complex_meta )
elseif imag == "-" then
return setmetatable( { 0,-1 }, complex_meta )
end
if string.lower(string.sub(imag,1,1)) ~= "e" then
imag = loadstring("return tonumber("..imag..")")
if imag then
return setmetatable( { 0,imag() }, complex_meta )
end
end
return
end
-- should be real
local real = string.match( num,"^(%-*[%d%.][%-%+%*%^%d%./Ee]*)$" )
if real then
real = loadstring( "return tonumber("..real..")" )
if real then
return setmetatable( { real(),0 }, complex_meta )
end
end
local real, imag = parse_complex(num)
return setmetatable( { real, imag }, complex_meta )
end
end
@ -170,7 +168,7 @@ end
-- complex.convpolardeg( r, phi )
-- convert polar coordinates ( r*e^(i*phi) ) to carthesic complex number
-- r (radius) is a number
-- phi must be in degrees; e.g. [0° - 360°]
-- phi must be in degrees; e.g. [0 - 360 deg]
function complex.convpolardeg( radius, phi )
phi = phi/180 * math.pi
return setmetatable( { radius * math.cos( phi ), radius * math.sin( phi ) }, complex_meta )
@ -219,7 +217,7 @@ end
-- complex.polardeg( cx )
-- from complex number to polar coordinates
-- output in degrees; [-180°,180°]
-- output in degrees; [-180, 180 deg]
-- returns r (radius), phi (angle)
function complex.polardeg( cx )
return math.sqrt( cx[1]^2 + cx[2]^2 ), math.atan2( cx[2], cx[1] ) / math.pi * 180
@ -421,4 +419,4 @@ return complex
--///////////////--
--// chillcode //--
--///////////////--
--///////////////--

View File

@ -8,16 +8,35 @@ assert( tostring( cx ) == "2+3i" )
cx = complex ( 2 )
assert( tostring( cx ) == "2" )
assert( cx:tostring() == 2 )
cx = complex "2^2+3/2i"
assert( tostring( cx ) == "4+1.5i" )
cx = complex ".5-2E-3i"
assert( tostring( cx ) == "0.5-0.002i" )
cx = complex "3i"
assert( tostring( cx ) == "3i" )
--old:no longer supported: assert( tostring(complex '2^2+3/2i') == '4+1.5i' )
assert( tostring( complex '.5-2E-3i' ) == '0.5-0.002i' )
assert( tostring( complex '0' ) == '0' )
assert( tostring( complex '10' ) == '10' )
assert( tostring( complex '10.2' ) == '10.2' )
assert( tostring( complex '-10.2' ) == '-10.2' )
assert( tostring( complex '-10.2e2' ) == '-1020' )
assert( tostring( complex '-10.2E+02' ) == '-1020' )
assert( tostring( complex 'i' ) == 'i' )
assert( tostring( complex '-i' ) == '-i' )
assert( tostring( complex '3i' ) == '3i' )
assert( tostring( complex '-3i' ) == '-3i' )
assert( tostring( complex '0-3i' ) == '-3i' )
assert( tostring( complex '1/+2+3/-4i' ) == '0.5-0.75i' )
assert( tostring( complex '1e+0/2.0-1e0/2.0i' ) == '0.5-0.5i' )
-- bad formatting
assert( not pcall(complex, '') )
assert( not pcall(complex, '2 + 4i') ) -- space
assert( not pcall(complex, '1+2i ') ) -- space
assert( not pcall(complex, 'i+1') ) -- reversed
assert( tostring(complex'2 ') == '2' ) --ok (space, not invoking tonumber directly)
assert( not pcall(complex, '-') )
assert( not pcall(complex, '++1') )
assert( not pcall(complex, '1/2/3') ) -- multiple operations
--
cx = complex "2"
assert( tostring( cx ) == "2" )
assert( cx:tostring() == 2 )
assert( complex "2 + 4i" == nil )
-- complex.new
cx = complex.new( 2,3 )