Advertisement
Guest User

Untitled

a guest
Dec 20th, 2014
183
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.63 KB | None | 0 0
  1. -- complex 0.3.0
  2. -- Lua 5.1
  3.  
  4. -- 'complex' provides common tasks with complex numbers
  5.  
  6. -- function complex.to( arg ); complex( arg )
  7. -- returns a complex number on success, nil on failure
  8. -- arg := number or { number,number } or ( "(-)<number>" and/or "(+/-)<number>i" )
  9. -- e.g. 5; {2,3}; "2", "2+i", "-2i", "2^2*3+1/3i"
  10. -- note: 'i' is always in the numerator, spaces are not allowed
  11.  
  12. -- a complex number is defined as carthesic complex number
  13. -- complex number := { real_part, imaginary_part }
  14. -- this gives fast access to both parts of the number for calculation
  15. -- the access is faster than in a hash table
  16. -- the metatable is just a add on, when it comes to speed, one is faster using a direct function call
  17.  
  18. -- http://luaforge.net/projects/LuaMatrix
  19. -- http://lua-users.org/wiki/ComplexNumbers
  20.  
  21. -- Licensed under the same terms as Lua itself.
  22.  
  23. --/////////////--
  24. --// complex //--
  25. --/////////////--
  26.  
  27. -- link to complex table
  28. local complex = {}
  29.  
  30. -- link to complex metatable
  31. local complex_meta = {}
  32.  
  33. -- complex.to( arg )
  34. -- return a complex number on success
  35. -- return nil on failure
  36. local _retone = function() return 1 end
  37. local _retminusone = function() return -1 end
  38. function complex.to( num )
  39. -- check for table type
  40. if type( num ) == "table" then
  41. -- check for a complex number
  42. if getmetatable( num ) == complex_meta then
  43. return num
  44. end
  45. local real,imag = tonumber( num[1] ),tonumber( num[2] )
  46. if real and imag then
  47. return setmetatable( { real,imag }, complex_meta )
  48. end
  49. return
  50. end
  51. -- check for number
  52. local isnum = tonumber( num )
  53. if isnum then
  54. return setmetatable( { isnum,0 }, complex_meta )
  55. end
  56. if type( num ) == "string" then
  57. -- check for real and complex
  58. -- number chars [%-%+%*%^%d%./Ee]
  59. local real,sign,imag = string.match( num, "^([%-%+%*%^%d%./Ee]*%d)([%+%-])([%-%+%*%^%d%./Ee]*)i$" )
  60. if real then
  61. if string.lower(string.sub(real,1,1)) == "e"
  62. or string.lower(string.sub(imag,1,1)) == "e" then
  63. return
  64. end
  65. if imag == "" then
  66. if sign == "+" then
  67. imag = _retone
  68. else
  69. imag = _retminusone
  70. end
  71. elseif sign == "+" then
  72. imag = loadstring("return tonumber("..imag..")")
  73. else
  74. imag = loadstring("return tonumber("..sign..imag..")")
  75. end
  76. real = loadstring("return tonumber("..real..")")
  77. if real and imag then
  78. return setmetatable( { real(),imag() }, complex_meta )
  79. end
  80. return
  81. end
  82. -- check for complex
  83. local imag = string.match( num,"^([%-%+%*%^%d%./Ee]*)i$" )
  84. if imag then
  85. if imag == "" then
  86. return setmetatable( { 0,1 }, complex_meta )
  87. elseif imag == "-" then
  88. return setmetatable( { 0,-1 }, complex_meta )
  89. end
  90. if string.lower(string.sub(imag,1,1)) ~= "e" then
  91. imag = loadstring("return tonumber("..imag..")")
  92. if imag then
  93. return setmetatable( { 0,imag() }, complex_meta )
  94. end
  95. end
  96. return
  97. end
  98. -- should be real
  99. local real = string.match( num,"^(%-*[%d%.][%-%+%*%^%d%./Ee]*)$" )
  100. if real then
  101. real = loadstring( "return tonumber("..real..")" )
  102. if real then
  103. return setmetatable( { real(),0 }, complex_meta )
  104. end
  105. end
  106. end
  107. end
  108.  
  109. -- complex( arg )
  110. -- same as complex.to( arg )
  111. -- set __call behaviour of complex
  112. setmetatable( complex, { __call = function( _,num ) return complex.to( num ) end } )
  113.  
  114. -- complex.new( real, complex )
  115. -- fast function to get a complex number, not invoking any checks
  116. function complex.new( ... )
  117. return setmetatable( { ... }, complex_meta )
  118. end
  119.  
  120. -- complex.type( arg )
  121. -- is argument of type complex
  122. function complex.type( arg )
  123. if getmetatable( arg ) == complex_meta then
  124. return "complex"
  125. end
  126. end
  127.  
  128. -- complex.convpolar( r, phi )
  129. -- convert polar coordinates ( r*e^(i*phi) ) to carthesic complex number
  130. -- r (radius) is a number
  131. -- phi (angle) must be in radians; e.g. [0 - 2pi]
  132. function complex.convpolar( radius, phi )
  133. return setmetatable( { radius * math.cos( phi ), radius * math.sin( phi ) }, complex_meta )
  134. end
  135.  
  136. -- complex.convpolardeg( r, phi )
  137. -- convert polar coordinates ( r*e^(i*phi) ) to carthesic complex number
  138. -- r (radius) is a number
  139. -- phi must be in degrees; e.g. [0° - 360°]
  140. function complex.convpolardeg( radius, phi )
  141. phi = phi/180 * math.pi
  142. return setmetatable( { radius * math.cos( phi ), radius * math.sin( phi ) }, complex_meta )
  143. end
  144.  
  145. --// complex number functions only
  146.  
  147. -- complex.tostring( cx [, formatstr] )
  148. -- to string or real number
  149. -- takes a complex number and returns its string value or real number value
  150. function complex.tostring( cx,formatstr )
  151. local real,imag = cx[1],cx[2]
  152. if formatstr then
  153. if imag == 0 then
  154. return string.format( formatstr, real )
  155. elseif real == 0 then
  156. return string.format( formatstr, imag ).."i"
  157. elseif imag > 0 then
  158. return string.format( formatstr, real ).."+"..string.format( formatstr, imag ).."i"
  159. end
  160. return string.format( formatstr, real )..string.format( formatstr, imag ).."i"
  161. end
  162. if imag == 0 then
  163. return real
  164. elseif real == 0 then
  165. return ((imag==1 and "") or (imag==-1 and "-") or imag).."i"
  166. elseif imag > 0 then
  167. return real.."+"..(imag==1 and "" or imag).."i"
  168. end
  169. return real..(imag==-1 and "-" or imag).."i"
  170. end
  171.  
  172. -- complex.print( cx [, formatstr] )
  173. -- print a complex number
  174. function complex.print( ... )
  175. print( complex.tostring( ... ) )
  176. end
  177.  
  178. -- complex.polar( cx )
  179. -- from complex number to polar coordinates
  180. -- output in radians; [-pi,+pi]
  181. -- returns r (radius), phi (angle)
  182. function complex.polar( cx )
  183. return math.sqrt( cx[1]^2 + cx[2]^2 ), math.atan2( cx[2], cx[1] )
  184. end
  185.  
  186. -- complex.polardeg( cx )
  187. -- from complex number to polar coordinates
  188. -- output in degrees; [-180°,180°]
  189. -- returns r (radius), phi (angle)
  190. function complex.polardeg( cx )
  191. return math.sqrt( cx[1]^2 + cx[2]^2 ), math.atan2( cx[2], cx[1] ) / math.pi * 180
  192. end
  193.  
  194. -- complex.mulconjugate( cx )
  195. -- multiply with conjugate, function returning a number
  196. function complex.mulconjugate( cx )
  197. return cx[1]^2 + cx[2]^2
  198. end
  199.  
  200. -- complex.abs( cx )
  201. -- get the absolute value of a complex number
  202. function complex.abs( cx )
  203. return math.sqrt( cx[1]^2 + cx[2]^2 )
  204. end
  205.  
  206. -- complex.get( cx )
  207. -- returns real_part, imaginary_part
  208. function complex.get( cx )
  209. return cx[1],cx[2]
  210. end
  211.  
  212. -- complex.set( cx, real, imag )
  213. -- sets real_part = real and imaginary_part = imag
  214. function complex.set( cx,real,imag )
  215. cx[1],cx[2] = real,imag
  216. end
  217.  
  218. -- complex.is( cx, real, imag )
  219. -- returns true if, real_part = real and imaginary_part = imag
  220. -- else returns false
  221. function complex.is( cx,real,imag )
  222. if cx[1] == real and cx[2] == imag then
  223. return true
  224. end
  225. return false
  226. end
  227.  
  228. --// functions returning a new complex number
  229.  
  230. -- complex.copy( cx )
  231. -- copy complex number
  232. function complex.copy( cx )
  233. return setmetatable( { cx[1],cx[2] }, complex_meta )
  234. end
  235.  
  236. -- complex.add( cx1, cx2 )
  237. -- add two numbers; cx1 + cx2
  238. function complex.add( cx1,cx2 )
  239. return setmetatable( { cx1[1]+cx2[1], cx1[2]+cx2[2] }, complex_meta )
  240. end
  241.  
  242. -- complex.sub( cx1, cx2 )
  243. -- subtract two numbers; cx1 - cx2
  244. function complex.sub( cx1,cx2 )
  245. return setmetatable( { cx1[1]-cx2[1], cx1[2]-cx2[2] }, complex_meta )
  246. end
  247.  
  248. -- complex.mul( cx1, cx2 )
  249. -- multiply two numbers; cx1 * cx2
  250. function complex.mul( cx1,cx2 )
  251. return setmetatable( { cx1[1]*cx2[1] - cx1[2]*cx2[2],cx1[1]*cx2[2] + cx1[2]*cx2[1] }, complex_meta )
  252. end
  253.  
  254. -- complex.mulnum( cx, num )
  255. -- multiply complex with number; cx1 * num
  256. function complex.mulnum( cx,num )
  257. return setmetatable( { cx[1]*num,cx[2]*num }, complex_meta )
  258. end
  259.  
  260. -- complex.div( cx1, cx2 )
  261. -- divide 2 numbers; cx1 / cx2
  262. function complex.div( cx1,cx2 )
  263. -- get complex value
  264. local val = cx2[1]^2 + cx2[2]^2
  265. -- multiply cx1 with conjugate complex of cx2 and divide through val
  266. return setmetatable( { (cx1[1]*cx2[1]+cx1[2]*cx2[2])/val,(cx1[2]*cx2[1]-cx1[1]*cx2[2])/val }, complex_meta )
  267. end
  268.  
  269. -- complex.divnum( cx, num )
  270. -- divide through a number
  271. function complex.divnum( cx,num )
  272. return setmetatable( { cx[1]/num,cx[2]/num }, complex_meta )
  273. end
  274.  
  275. -- complex.pow( cx, num )
  276. -- get the power of a complex number
  277. function complex.pow( cx,num )
  278. if math.floor( num ) == num then
  279. if num < 0 then
  280. local val = cx[1]^2 + cx[2]^2
  281. cx = { cx[1]/val,-cx[2]/val }
  282. num = -num
  283. end
  284. local real,imag = cx[1],cx[2]
  285. for i = 2,num do
  286. real,imag = real*cx[1] - imag*cx[2],real*cx[2] + imag*cx[1]
  287. end
  288. return setmetatable( { real,imag }, complex_meta )
  289. end
  290. -- we calculate the polar complex number now
  291. -- since then we have the versatility to calc any potenz of the complex number
  292. -- then we convert it back to a carthesic complex number, we loose precision here
  293. local length,phi = math.sqrt( cx[1]^2 + cx[2]^2 )^num, math.atan2( cx[2], cx[1] )*num
  294. return setmetatable( { length * math.cos( phi ), length * math.sin( phi ) }, complex_meta )
  295. end
  296.  
  297. -- complex.sqrt( cx )
  298. -- get the first squareroot of a complex number, more accurate than cx^.5
  299. function complex.sqrt( cx )
  300. local len = math.sqrt( cx[1]^2+cx[2]^2 )
  301. local sign = (cx[2]<0 and -1) or 1
  302. return setmetatable( { math.sqrt((cx[1]+len)/2), sign*math.sqrt((len-cx[1])/2) }, complex_meta )
  303. end
  304.  
  305. -- complex.ln( cx )
  306. -- natural logarithm of cx
  307. function complex.ln( cx )
  308. return setmetatable( { math.log(math.sqrt( cx[1]^2 + cx[2]^2 )),
  309. math.atan2( cx[2], cx[1] ) }, complex_meta )
  310. end
  311.  
  312. -- complex.exp( cx )
  313. -- exponent of cx (e^cx)
  314. function complex.exp( cx )
  315. local expreal = math.exp(cx[1])
  316. return setmetatable( { expreal*math.cos(cx[2]), expreal*math.sin(cx[2]) }, complex_meta )
  317. end
  318.  
  319. -- complex.conjugate( cx )
  320. -- get conjugate complex of number
  321. function complex.conjugate( cx )
  322. return setmetatable( { cx[1], -cx[2] }, complex_meta )
  323. end
  324.  
  325. -- complex.round( cx [,idp] )
  326. -- round complex numbers, by default to 0 decimal points
  327. function complex.round( cx,idp )
  328. local mult = 10^( idp or 0 )
  329. return setmetatable( { math.floor( cx[1] * mult + 0.5 ) / mult,
  330. math.floor( cx[2] * mult + 0.5 ) / mult }, complex_meta )
  331. end
  332.  
  333. --// metatable functions
  334.  
  335. complex_meta.__add = function( cx1,cx2 )
  336. local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 )
  337. return complex.add( cx1,cx2 )
  338. end
  339. complex_meta.__sub = function( cx1,cx2 )
  340. local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 )
  341. return complex.sub( cx1,cx2 )
  342. end
  343. complex_meta.__mul = function( cx1,cx2 )
  344. local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 )
  345. return complex.mul( cx1,cx2 )
  346. end
  347. complex_meta.__div = function( cx1,cx2 )
  348. local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 )
  349. return complex.div( cx1,cx2 )
  350. end
  351. complex_meta.__pow = function( cx,num )
  352. if num == "*" then
  353. return complex.conjugate( cx )
  354. end
  355. return complex.pow( cx,num )
  356. end
  357. complex_meta.__unm = function( cx )
  358. return setmetatable( { -cx[1], -cx[2] }, complex_meta )
  359. end
  360. complex_meta.__eq = function( cx1,cx2 )
  361. if cx1[1] == cx2[1] and cx1[2] == cx2[2] then
  362. return true
  363. end
  364. return false
  365. end
  366. complex_meta.__tostring = function( cx )
  367. return tostring( complex.tostring( cx ) )
  368. end
  369. complex_meta.__concat = function( cx,cx2 )
  370. return tostring(cx)..tostring(cx2)
  371. end
  372. -- cx( cx, formatstr )
  373. complex_meta.__call = function( ... )
  374. print( complex.tostring( ... ) )
  375. end
  376. complex_meta.__index = {}
  377. for k,v in pairs( complex ) do
  378. complex_meta.__index[k] = v
  379. end
  380.  
  381. return complex
  382.  
  383. --///////////////--
  384. --// chillcode //--
  385. --///////////////--
  386. Testcode:
  387.  
  388. local complex = require "complex"
  389.  
  390. local cx,cx1,cx2,re,im
  391.  
  392. -- complex.to / complex call
  393. cx = complex { 2,3 }
  394. assert( tostring( cx ) == "2+3i" )
  395. cx = complex ( 2 )
  396. assert( tostring( cx ) == "2" )
  397. assert( cx:tostring() == 2 )
  398. cx = complex "2^2+3/2i"
  399. assert( tostring( cx ) == "4+1.5i" )
  400. cx = complex ".5-2E-3i"
  401. assert( tostring( cx ) == "0.5-0.002i" )
  402. cx = complex "3i"
  403. assert( tostring( cx ) == "3i" )
  404. cx = complex "2"
  405. assert( tostring( cx ) == "2" )
  406. assert( cx:tostring() == 2 )
  407. assert( complex "2 + 4i" == nil )
  408.  
  409. -- complex.new
  410. cx = complex.new( 2,3 )
  411. assert( tostring( cx ) == "2+3i" )
  412.  
  413. -- complex.type
  414. assert( complex.type( cx ) == "complex" )
  415. assert( complex.type( {} ) == nil )
  416.  
  417. -- complex.convpolar( radius, phi )
  418. assert( complex.convpolar( 3, 0 ):round(10) == complex "3" )
  419. assert( complex.convpolar( 3, math.pi/2 ):round(10) == complex "3i" )
  420. assert( complex.convpolar( 3, math.pi ):round(10) == complex "-3" )
  421. assert( complex.convpolar( 3, math.pi*3/2 ):round(10) == complex "-3i" )
  422. assert( complex.convpolar( 3, math.pi*2 ):round(10) == complex "3" )
  423.  
  424. -- complex.convpolardeg( radius, phi )
  425. assert( complex.convpolardeg( 3, 0 ):round(10) == complex "3" )
  426. assert( complex.convpolardeg( 3, 90 ):round(10) == complex "3i" )
  427. assert( complex.convpolardeg( 3, 180 ):round(10) == complex "-3" )
  428. assert( complex.convpolardeg( 3, 270 ):round(10) == complex "-3i" )
  429. assert( complex.convpolardeg( 3, 360 ):round(10) == complex "3" )
  430.  
  431. -- complex.tostring( cx,formatstr )
  432. cx = complex "2+3i"
  433. assert( complex.tostring( cx ) == "2+3i" )
  434. assert( complex.tostring( cx, "%.2f" ) == "2.00+3.00i" )
  435. -- does not support a second argument
  436. assert( tostring( cx, "%.2f" ) == "2+3i" )
  437.  
  438. -- complex.polar( cx )
  439. local r,phi = complex.polar( {3,0} )
  440. assert( r == 3 )
  441. assert( phi == 0 )
  442.  
  443. local r,phi = complex.polar( {0,3} )
  444. assert( r == 3 )
  445. assert( phi == math.pi/2 )
  446.  
  447. local r,phi = complex.polar( {-3,0} )
  448. assert( r == 3 )
  449. assert( phi == math.pi )
  450.  
  451. local r,phi = complex.polar( {0,-3} )
  452. assert( r == 3 )
  453. assert( phi == -math.pi/2 )
  454.  
  455. -- complex.polardeg( cx )
  456. local r,phi = complex.polardeg( {3,0} )
  457. assert( r == 3 )
  458. assert( phi == 0 )
  459.  
  460. local r,phi = complex.polardeg( {0,3} )
  461. assert( r == 3 )
  462. assert( phi == 90 )
  463.  
  464. local r,phi = complex.polardeg( {-3,0} )
  465. assert( r == 3 )
  466. assert( phi == 180 )
  467.  
  468. local r,phi = complex.polardeg( {0,-3} )
  469. assert( r == 3 )
  470. assert( phi == -90 )
  471.  
  472. -- complex.mulconjugate( cx )
  473. cx = complex "2+3i"
  474. assert( complex.mulconjugate( cx ) == 13 )
  475.  
  476. -- complex.abs( cx )
  477. cx = complex "3+4i"
  478. assert( complex.abs( cx ) == 5 )
  479.  
  480. -- complex.get( cx )
  481. cx = complex "2+3i"
  482. re,im = complex.get( cx )
  483. assert( re == 2 )
  484. assert( im == 3 )
  485.  
  486. -- complex.set( cx, re, im )
  487. cx = complex "2+3i"
  488. complex.set( cx, 3, 2 )
  489. assert( cx == complex "3+2i" )
  490.  
  491. -- complex.is( cx, re, im )
  492. cx = complex "2+3i"
  493. assert( complex.is( cx, 2, 3 ) == true )
  494. assert( complex.is( cx, 3, 2 ) == false )
  495.  
  496. -- complex.copy( cx )
  497. cx = complex "2+3i"
  498. cx1 = complex.copy( cx )
  499. complex.set( cx, 1, 1 )
  500. assert( cx1 == complex "2+3i" )
  501.  
  502. -- complex.add( cx1, cx2 )
  503. cx1 = complex "2+3i"
  504. cx2 = complex "3+2i"
  505. assert( complex.add(cx1,cx2) == complex "5+5i" )
  506.  
  507. -- complex.sub( cx1, cx2 )
  508. cx1 = complex "2+3i"
  509. cx2 = complex "3+2i"
  510. assert( complex.sub(cx1,cx2) == complex "-1+1i" )
  511.  
  512. -- complex.mul( cx1, cx2 )
  513. cx1 = complex "2+3i"
  514. cx2 = complex "3+2i"
  515. assert( complex.mul(cx1,cx2) == complex "13i" )
  516.  
  517. -- complex.mulnum( cx, num )
  518. cx = complex "2+3i"
  519. assert( complex.mulnum( cx, 2 ) == complex "4+6i" )
  520.  
  521. -- complex.div( cx1, cx2 )
  522. cx1 = complex "2+3i"
  523. cx2 = complex "3-2i"
  524. assert( complex.div(cx1,cx2) == complex "i" )
  525.  
  526. -- complex.divnum( cx, num )
  527. cx = complex "2+3i"
  528. assert( complex.divnum( cx, 2 ) == complex "1+1.5i" )
  529.  
  530. -- complex.pow( cx, num )
  531. cx = complex "2+3i"
  532. assert( complex.pow( cx, 3 ) == complex "-46+9i" )
  533.  
  534. cx = complex( -121 )
  535. cx = cx^.5
  536. -- we have to round here due to the polar calculation of the squareroot
  537. cx = cx:round( 10 )
  538. assert( cx == complex "11i" )
  539.  
  540. cx = complex"2+3i"
  541. assert( cx^-2 ~= 1/cx^2 )
  542. assert( cx^-2 == (cx^-1)^2 )
  543. assert( tostring( cx^-2 ) == tostring( 1/cx^2 ) )
  544.  
  545. -- complex.sqrt( cx )
  546. cx = complex( -121 )
  547. assert( complex.sqrt( cx ) == complex "11i" )
  548. cx = complex "2-3i"
  549. cx = cx^2
  550. assert( cx:sqrt() == complex "2-3i" )
  551.  
  552. -- complex.ln( cx )
  553. cx = complex "3+4i"
  554. assert( cx:ln():round( 4 ) == complex "1.6094+0.9273i" )
  555.  
  556. -- complex.exp( cx )
  557. cx = complex "2+3i"
  558. assert( cx:ln():exp() == complex "2+3i" )
  559.  
  560. -- complex.conjugate( cx )
  561. cx = complex "2+3i"
  562. assert( cx:conjugate() == complex "2-3i" )
  563.  
  564. -- metatable
  565.  
  566. -- __add
  567. cx = complex "2+3i"
  568. assert( cx+2 == complex "4+3i" )
  569.  
  570. -- __unm
  571. cx = complex "2+3i"
  572. assert( -cx == complex "-2-3i" )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement