Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Constructing complex numbers using recursion

by moltar512 (Sexton)
on Nov 08, 2005 at 04:23 UTC ( [id://506596]=perlquestion: print w/replies, xml ) Need Help??

moltar512 has asked for the wisdom of the Perl Monks concerning the following question:

hi I have a very big code file i won't bore you with
I will paraphrase what it does, and maybe you can help me figure out why its crashing/giving me an infinite loop

what it does is take a string and pick out the real/complex part if it is in rectangular form, or pick out the magnitude and angle if it is in polar form. What i want is if it is in polar form, i want to make the real/complex data represented in @constructed reflect the polar form of the rectangular data. So, really, in order to get this data, i'm trying to get constructComplex to call itself.
$x = "3 _ 4"; #in polar form.. 3 is mag and 4 is angle sub constructComplex{ my($value1, $real, $complex, $magnitude, $angle, @construct, @const +ructPolar, $isinPolarForm, $isinRectForm); $value1 = $_[0]; if($isinPolarForm) { #uses $value1 to pick out the magnitude and angle $magnitude = blah; $angle = blah; ###point of interest### @constructPolar = &constructComplex(&PolarToRect($value1)); $real = $constructPolar[0]; $complex = $constructPolar[2]; ###point of interest### } if($isinRectForm) { $real = blah; $complex = blah; #haven't implemented getting polar values from rect form because + getting the rect values from polar doesn't work yet } $construct[0] = $real; $construct[1] = $complex; $construct[2] = $magnitude; $construct[3] = $angle; } sub PolarToRect { my($magnitude, $angle, $real, $complex); #does it return $magnitude . " _ " $angle; }

2005-11-08 Retitled by broquaint, as per Monastery guidelines
Original title: 'Recursion!!'

Replies are listed 'Best First'.
Re: Constructing complex numbers using recursion
by duff (Parson) on Nov 08, 2005 at 04:44 UTC
    I will paraphrase what it does, and maybe you can help me figure out why its crashing/giving me an infinite loop

    Well, it's hard figure out what's really going on from a "paraphrase" but if there is infinite loop, it's probably because constructComplex() calls itself recursively and the conditions that mediate the recusion do not change.

    Here's my advice though: use Math::Trig. It has routines that convert from/to polar coordinates and a whole lot more.

Re: Constructing complex numbers using recursion
by GrandFather (Saint) on Nov 08, 2005 at 04:30 UTC

    Do you use use warnings; use strict? As it stands, and ignoring the gratuitous blah stuff, this is broken code. On the face of it $real = @constructPolar[0]; is not valid. There are other similar problems.

    Try to put together an example that can actually be run and demonstrates the problem.


    Perl is Huffman encoded by design.
      oh ya, i do use warnings and strict
      you guys have yelled at me about that before ;)

      checking my code, i do have $real = $constructPolar[0].. my mistake

      My code is really really long.. haha..
      this is the general idea of what it is doing.. without the stuff I marked as interesting it is working okay. I figured there might be a weird reason i couldn't just do recursion like i was trying to. I don't think it should infinitely loop.. i don't see how it could.. but it doesn't make any sense why it should make my system hang when i try to run/compile it

        Where do $isinPolarForm, $isinRectForm get set?


        Perl is Huffman encoded by design.
Re: Constructing complex numbers using recursion
by graff (Chancellor) on Nov 08, 2005 at 04:41 UTC
    It would be a lot better for all concerned if you could post a version of the code that actually compiles and runs (even if it runs in an endless loop). The code you posted has no usable sample data, plus a syntax error in the "PolarToRect" sub (you're missing a period between " _ " and $angle) -- and maybe it wouldn't be to awful to actually include the full code for that sub.

    Based on what you've shown, it looks like the value being passed to the "recursed" constructComplex (i.e. the return value from PolarToRect) might be incorrect in some way -- but there's really no way to be sure, because the OP has left out some important parts.

    (Like: when "$magnitude = blah", does this mean that it gets the part of a string that precedes " _ "? and similarly for "$angle = blah"?)

    update: for that matter, I'm having trouble understanding why "constructComplex" is calling itself at all here... if the coordinates are "inPolarForm", why do you need to convert to rectangular and then back to polar?

      the purpose of constructComplex ultimately is to take the strings that i give it (either in "3 _ 4" form or "3 + 4i" form) and pick out the numbers from the rest of the string.


      what i'm trying to do is if constructComplex detects that value1 is of type polar (if i get this fix i'd like to expand this to all other cases), i want it to get the rectangular form from PolarToRect and then use constructComplex (the recursion) to pick out the real/complex numbers and package all of that nicely in the @construct that constructComplex returns at the end
Re: Constructing complex numbers using recursion
by GrandFather (Saint) on Nov 08, 2005 at 04:52 UTC

    You may find this an interesting starting point:

    use strict; use warnings; my $x = "3 _ 4"; #in polar form.. 3 is mag and 4 is angle my $y = "1i2"; #in rectangular form print join ", ", constructComplex ($x); print "\n" . join ", ", constructComplex ($y); sub constructComplex { my $value1 = shift; my @construct; my ($a, $Form, $b) = $value1 =~ /([-+e.\d]+)\s*([i_])\s*([-+e.\d]+)/; return undef if ! defined $b; $value1 = $_[0]; if ($Form eq '_') { #uses $value1 to pick out the magnitude and angle my ($magnitude, $angle) = ($a, $b); $construct[2] = $magnitude; $construct[3] = $angle; # Do da polar to rect conversion } else { my ($real, $complex) = ($a, $b); $construct[0] = $real; $construct[1] = $complex; # Do da rect to polar conversion } return @construct; }

    Ignoring undef related warnings it prints:

    , , 3, 4 1, 2

    Perl is Huffman encoded by design.
      ya.. i'm way to green to read regular expressions :( :(
      here is my constructComplex method in it's entirety, for extreme clarity
      sub constructComplex { my $value1 = $_[0]; my $value2 = $_[1]; my ($real1, $real2, $complex1, $complex2, $magnitude1, $magnitude2 +, $angle1, $angle2, @constructed, @constructedvalue1Polar, @construc +tedvalue1Rect, @constructedvalue2Polar, @constructedvalue2Rect, $valu +e1isRectangular, $value2isRectangular); #if value1 is in rectangular form if(rindex($value1, "_") < 0) { $value1isRectangular = 1; } #if value1 is in polar form if(rindex($value1, "_") > 0) { $value1isRectangular = 0; $magnitude1 = substr($value1, 0, index($value1, " ")); $angle1 =substr($value1, (rindex($value1, " ") + 1), length($v +alue1)); #@constructedvalue1Polar = &constructComplex(&PolarToRect($val +ue1)); #$real1 = $constructedvalue1Polar[0]; #$complex1 = $constructedvalue1Polar[2]; } #if value2 is in rectangular form if(rindex($value2, "_") < 0) { $value2isRectangular = 1; } #if value2 is in polar form if(rindex($value2, "_") > 0) { $value2isRectangular = 0; $magnitude2 = substr($value2, 0, index($value2, " ")); $angle2 =substr($value2, (rindex($value2, " ") + 1), length($v +alue2)); } ############## if($value1isRectangular) { #lowercases everything $value1 = lc($value1); #if a j is found, turns it into an i if(rindex($value1, "j") > 0) { substr ($value1, rindex($value1, "j"), 1, "i"); } #if there is no space, and there is no i, then there must ONLY + be a real part if(index($value1, " ") < 0 && index($value1, "i") < 0) { $real1 = substr($value1, 0, length($value1)); } #if there is no space, but there is an i, then there is no rea +l part, real is 0 elsif(index($value1, " ") < 0 && index($value1, "i") > 0) { $real1 = "0"; } #else, there is a space, meaning both real and complex else { $real1 = substr($value1, 0, index($value1, " ")); } #"7 + i" if((index($value1, " ") > 0) && (index($value1, "i") > 0) && ( +(rindex($value1, " ") + 1) == index($value1, "i"))) { $complex1 = "1"; } #"7 + -i" and "-i" #elsif((index($value1, " ") > 0) && (index($value1, "i") > 0) +&& (index($value1, "-") > 0) && ((rindex($value1, " ") + 1) == rindex +($value1, "-")) && ((rindex($value1, "-") + 1) == rindex($value1, "i" +))) elsif(index($value1, "-i") != -1) { $complex1 = "-1"; } #"i" elsif((index($value1, "i") == 0)) { $complex1 = "1"; } #"-Bi" elsif((index($value1, " ") < 0) && (index($value1, "i") > 0) & +& (index($value1, "-") != -1) && (index($value1, "i") != 0) && ((inde +x($value1, "-") +1) != index($value1, "i"))) { $complex1 = substr($value1, 0, index($value1, "i")); } #"Bi" elsif((index($value1, " ") < 0) && (index($value1, "i") > 0) & +& (index($value1, "-") < 0) && (index($value1, "i") != 0)) { $complex1 = substr($value1, 0, index($value1, "i")); } #"30" elsif(index($value1, "i") < 0) { $complex1 = 0 } else { $complex1 = substr($value1, (rindex($value1, " ") + 1), in +dex($value1, "i")); } #if negative by sign, changes element to negative if(index($value1, " - ") > 0) { $complex1 = -$complex1; } } if($value2isRectangular) { #lowercases everything $value2 = lc($value2); #if a j is found, turns it into an i if(rindex($value2, "j") > 0) { substr ($value2, rindex($value2, "j"), 1, "i"); } #if there is no space, and there is no i, then there must ONLY + be a real part if(index($value2, " ") < 0 && index($value2, "i") < 0) { $real2 = substr($value2, 0, length($value2)); } #if there is no space, but there is an i, then there is no rea +l part, real is 0 elsif(index($value2, " ") < 0 && index($value2, "i") > 0) { $real2 = "0"; } #else, there is a space, meaning both real and complex else { $real2 = substr($value2, 0, index($value2, " ")); } #"7 + i" if((index($value2, " ") > 0) && (index($value2, "i") > 0) && ( +(rindex($value2, " ") + 1) == index($value2, "i"))) { $complex2 = "1"; } #"7 + -i" and "-i" #elsif((index($value2, " ") > 0) && (index($value2, "i") > 0) +&& (index($value2, "-") > 0) && ((rindex($value2, " ") + 1) == rindex +($value2, "-")) && ((rindex($value2, "-") + 1) == rindex($value2, "i" +))) elsif(index($value2, "-i") != -1) { $complex2 = "-1"; } #"i" elsif((index($value2, "i") == 0)) { $complex2 = "1"; } #"-Bi" elsif((index($value2, " ") < 0) && (index($value2, "i") > 0) & +& (index($value2, "-") != -1) && (index($value2, "i") != 0) && ((inde +x($value2, "-") +1) != index($value2, "i"))) { $complex2 = substr($value2, 0, index($value2, "i")); } #"Bi" elsif((index($value2, " ") < 0) && (index($value2, "i") > 0) & +& (index($value2, "-") < 0) && (index($value2, "i") != 0)) { $complex2 = substr($value2, 0, index($value2, "i")); } #"30" elsif(index($value2, "i") < 0) { $complex2 = 0 } else { $complex2 = substr($value2, (rindex($value2, " ") + 1), in +dex($value2, "i")); } #if negative by sign, changes element to negative if(index($value2, " - ") > 0) { $complex2 = -$complex2; } } #if($real1 ||= 0) {$real1 = 0}; #if($real2 ||= 0) {$real2 = 0}; #if($complex1 ||= 0) {$complex1 = 0}; #if($complex2 ||= 0) {$complex2 = 0}; $constructed[0] = $real1; $constructed[1] = $real2; $constructed[2] = $complex1; $constructed[3] = $complex2; $constructed[4] = $magnitude1; $constructed[5] = $magnitude2; $constructed[6] = $angle1; $constructed[7] = $angle2; #return "R1: " . $real1 . " C1: " . $complex1 . " R2: " . $real2 . " C +2: " . $complex2 . " M1: " . $magnitude1 . " A1: " . $angle1 . " M2: +" . $magnitude2 . " A2: " . $angle2; return @constructed; } sub PolarToRect { my ($value1, $real1, $complex1, $magnitude1, $angle1, $complex, @const +ruct); $value1 = $_[0]; @construct = &constructComplex($value1); $magnitude1 = $construct[4]; $angle1 = $construct[6]; #return "M: " . $magnitude1 . " A: " . $angle1; $real1 = $magnitude1*cos($angle1*($pi/180)); $complex1 = $magnitude1*sin($angle1*($pi/180)); #return "R: " . $real1 . " C: " . $complex1; if($complex1 < 0) { $complex = $real1 . " - " . -$complex1 . "i"; } else { $complex = $real1 . " + " . $complex1 . "i"; } } my $z = "5 _ 36.87"; my $y = "6 _ 45.67"; print PolarToRect($z) . "\n";

        That is not extreme clarity, that is extreme obfusication! Too much code to illustrate a simple problem.

        A lot of the power in Perl involves regexen, learn to use them! Have a look at perlretut and perlre. Search for regex - it's a topic that comes up often. Play with regexen and ask questions about them. If you are using Perl you are using regexen or you are not doing it Right.

        Go back to my sample and pick it appart until you understand it, or ask specific questions - after reading the documentation linked above.


        Perl is Huffman encoded by design.
        Grandfather is right -- this is the extreme opposite of clarity.

        You definitely want to start over, and Grandfather's code is a good place to start. Programming hint: if you had structured your original "constructComplex" sub so that it keeps its two input args in an array and loops over each array element, you would have had about one half as many lines of code. That's true no matter what language you think in. And once you get used to thinking in Perl (and learn something about regexes), you'll be able to shorten -- and clarify -- the code quite a lot more.

Re: Constructing complex numbers using recursion
by pg (Canon) on Nov 08, 2005 at 05:12 UTC

    By looking at your original code and your explanation how you judge whether it is polar form, it is clear that your code is a dead loop.

    Your constructComplex() calls itself unless it is not in polar form. The way you check whether it is in polar form is to see whether there is a _ in the middle of the string (not the first char). You does that PolarToRect() convertion, however the return tells us that the rect form also has a _ in it. Now your rect form seems to the computer as a polar form because of that _ in the middle... So your program just goes on and on, as it never sees an input that is not polar form based on its judgement.

      okay.. i'm having a bit of trouble following you..

      this is my reasoning...

      I have a polar value
      once i convert this to rectangular.. it is in rectangular form.. there is no _ in the rectangular form and there never will be.. therefore i thought that a _ would be a great way to see if a value is polar or rectangular (it can only be one or the other).

      once it is back in rectangular form, i run constructComplex again to reap the numbers from the rectangular form.. and then i want to take those numbers and pass them back to the original calling of the constructComplex method...

      I don't understand where you say that the _ is in the rectangular form.. It can't be and it is not when i debug via the print method

      please be more clear??
        Here's a relevant quote from the OP at the start of this thread:
        sub PolarToRect { my($magnitude, $angle, $real, $complex); #does it return $magnitude . " _ " $angle; }
        Now, can you tell us, clearly: is this subroutine supposed to return a rectangular form for a set of polar coordinates? If that's true, then the rectangular form being returned by this subroutine contains a " _ " (assuming that you fix the syntax error, which I mentioned in an earlier reply). So this is why pg is saying that this is the cause of the infinite loop -- this sub is returning rectangular coords that contain " _ ", and the constructComplex is assuming that this means the value is still in polar form. So it calls itself again (and again and again...)

        update: Looking at your much longer (more detailed, more confusing!) reply to Grandfather, I see that the "running" version does not have this problem with " _ " in the "PolarToRect" sub. Your original post was just very misleading.

Re: Constructing complex numbers using recursion
by Anonymous Monk on Nov 08, 2005 at 17:14 UTC
    Make it easier on yourself and use stuff that's already available...
    #!/usr/bin/perl -w use strict; use Math::Complex; # http://perldoc.perl.org/Math/Complex.html my $a = toComplex("1-4i"); my $b = toComplex("2+7j"); my $c = toComplex("3 _ 2"); my $d = toComplex("5 _ 0.707"); $\ = "\n"; print $a + $b; print $c * $d; sub toComplex { my $str = shift; $str =~ tr/j/i/; # convert j's to i's $str =~ s/(.*)_(.*)/[$1,$2]/; # convert "_" into something that # Math::Complex will like return Math::Complex->make($str); }
Re: Constructing complex numbers using recursion
by swampyankee (Parson) on Nov 09, 2005 at 03:47 UTC

    This is quite straightforward trigonometry; there is absolutely no reason (except a homework assignment -- it isn't that, is it?) to use recursion. If you're trying to do this in an effort to do OO programming, it would make more sense (as someone mentioned before) to use Math::Trig or use Math::Complex or completely horrify the Perlmonks and use Fortran Smalltalk.

    The conversion formulae should be in any math book (I used Protter, MH and Morrey, CB College Calculus with Analytical Geometry, 2/ed, Addison Wesley Publishing, Co, Reading, Massachusetts: 1970, pp405-413).

    The Perl below will compile and give answers (they may even be the right answers) but I will not guarantee efficiency, elegance, or attractiveness.

    sub p2r { (my $r, my $theta) = @_; return ($r * cos($theta), $r * sin($theta)); # (x,y) } sub r2p { (my $x, my $y) = @_; my $theta = atan2($y, $x); my $r = ($x **2 + $y **2) ** (0.5); return ($r, $theta); }

    Of course, $theta is in radians.

    emc

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://506596]
Approved by graff
Front-paged by monkfan
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-04-24 03:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found