Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Simple algebraic calculations

by wanna_code_perl (Friar)
on Apr 18, 2014 at 17:33 UTC ( [id://1082791]=perlquestion: print w/replies, xml ) Need Help??

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

Edit

Thanks for all the replies. Here's a bit more information to answer (some) of your questions and comments:

This is not (really) a code factorization problem. Sure, purists will say "but, you can factor anything into a sub!", and basically rewrite Mathematica, but that would be a bit extreme for my purposes.

It's also not that I keep writing very similar half-life routines, or acceleration routines, or "which brand/size of cola is the cheapest", whatever... it's more the meta issues of how to represent units (and convert, automatically, when you take something like 9.8 m/s/s * 1 hour, how fast am I going?) By themselves, most of these things are simple, but en masse, and in combination, they're still "simple", but inelegant in Perl (or most any other general purpose language for that matter).

moritz and others, helped me decide that what I want is indeed probably a full symbolic math engine. It's either that or "factor" every formula and snippet I use into something that I'd probably end up being tempted writing a symbolic parser for anyway, which would be silly.

Original post follows.


Hello monks,

Over and over, I find myself writing little Perl scripts to do relatively simple calculations (but usually too many steps to be reasonable for a conventional calculator or spreadsheet). Management (and conversion) of units would be very important. Short of using a dedicated math language like Mathematica (or one of the free ones), is there anything in between, so I can still take advantage of Perl syntax for output, loops, CPAN modules, etc.?

Just one example of something I'd calculate would be various properties of the Half-life of a substance. Using the usual formulae, I'd want to calculate how much of the substance is left after N days (given a half life in hours), and then, given regular input of more substance, how long to reach a steady state. I won't bore you with the math, here; it's not especially difficult. See the above link for more information.

Writing pure Perl for this isn't difficult, but it is tedious and repetitive, especially given management of different units and conversions between.

My apologies for the rather vague specification of what I'm looking for, but that's part of the problem: I've thought about this more than once, and don't have a clear idea, aside from hiring a college student. :-)

Replies are listed 'Best First'.
Re: Simple algebraic calculations
by moritz (Cardinal) on Apr 18, 2014 at 19:56 UTC

    Since you mention algebraic in the title (but not in the body) of your question, I feel I have to ask: are you actually doing algebraic (symbolic) calculations?

    If yes, you should use a proper computer algebra system (Mathematica, Maple, Maxima, yacas, ...). Despite all the love for Perl, using a tool better suited for the job will save you lots of time and trouble.

    If no, Physics::Unit might be worth considering for the units management. I haven't use it before, but looks quite comprehensive to me.

    Regarding the repetitive aspect, it's a good idea to factor commonly use things out into subroutines, and collect them in a module. That way, repetitiveness reduces over time.

      If yes, you should use a proper computer algebra system (Mathematica, Maple, Maxima, yacas, ...). Despite all the love for Perl, using a tool better suited for the job will save you lots of time and trouble.

      Perhaps you are right. With all the difficulty I had coming up with a compelling example for discussion, that's probably a symptom of me trying to shove a square peg in a round hole. Yes, symbolic calculations would simplify most of what I'm doing, so maybe I should indeed use a full math language--I can always glue in a bit of Perl if absolutely necessary. Thank you.

Re: Simple algebraic calculations
by roboticus (Chancellor) on Apr 18, 2014 at 18:12 UTC

    wanna_code_perl:

    I don't have enough detail to know what you're finding tedious & repetitive. If you mean setting up the script and all the code around the simple calculations, then create a "boilerplate" template where you've got most of it set up, and just add a subroutine at the end to do the work.

    If you mean all the intermediate chunks of calculations, you can write simple subroutines to encapsulate much of it. If you gave us an example of what you're finding to be the tedious and repetitive parts, I'm sure someone may be able to come up with an idea to simplify things.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Simple algebraic calculations
by kcott (Archbishop) on Apr 18, 2014 at 23:51 UTC

    G'day wanna_code_perl,

    You're correct about this being a "rather vague specification". While I can get a general feel for what you want, I don't have any clear picture of:

    • How you intend to use these scripts. For instance, should I infer from "too many steps to be reasonable for a conventional calculator" that some unconventional calculator would be a useful and appropriate tool.
    • The complexity of units involved. Obviously, dealing with days and hours is simple (1 day equals 24 hours); but what about more complex time calculations (e.g. months of differing lengths, leap years, and so on). How many other types of measurement are you using and how simple or complex are the calculations involved with each of those?
    • The diversity of disciplines involved. For instance, half-life suggests that chemistry might be your field of interest; but, is chemistry the only area you're working with? is it a subset of a more general field? is it just one of many disparate fields?

    Keep all of those unknowns in mind while reading the following.

    Your problem domain seems to encompass two main areas: units and calculations.

    For "units", I'd split that into: canonical representation of a measurement type; and conversion between units in each measurement type. Any measurement that's input should be converted into the canonical unit (e.g. all lengths are represented as metres). All calculations use only the canonical unit. Conversion to some other unit is purely for output presentation. All of this could probably be done by a single module. (I probably wouldn't provide a public interface to this module.)

    For "calculations", I'd group those into one or modules (as appropriate — maybe one per discipline). These modules would access the "units" module. The API for any calculation would first convert all (unit) arguments to their canonical form. All internal functions would only use the canonical form. The API would provide some mechanism for presenting output in a non-canonical form.

    For the modules themselves, take a look at Exporter. Export nothing by default (@EXPORT = ();). Make liberal use of @EXPORT_OK and %EXPORT_TAGS such that indivual scripts can load just the functionality they need, e.g.

    use My::Chemistry::Module qw{specific_halflife_function};
    use My::Chemistry::Module qw{:all_halflife_functions};

    Decide on usage. You may want: a GUI representing an "unconventional calculator"; some sort of web interface; a commandline tool; or something else. If you keep the modules I described earlier clean (i.e. they perform just their intended functions without knowing, or caring, about who or what uses them), they could easily be used with any number of front-ends.

    There's probably many modules available to perform (at least some of) the conversions and calculations you want. Search in http://search.cpan.org/ to see what's available for your specific needs.

    -- Ken

Re: Simple algebraic calculations
by Laurent_R (Canon) on Apr 19, 2014 at 09:54 UTC

    Half lives are used for describing the time which is takes for a quantity of radioactive substance fall to half its original value. The units are to a large extent irrelevant to the calculation itself: the same formula applies whether the original quantity is expressed in kilograms, grams, pounds, moles, etc. The same is true about durations: you only need to express the half-life and the time in the same units to get a correct result, it does not matter if this common unit is seconds or billions of years.

    Given the probabilistic and exponential nature of the radioactive decay laws, you also don't really care about irregular month durations, leap years and the like. But usually, three main units are used for half-lives: seconds, days and years. You would usually not say that a given substance has a three-month half-life, because that would lack precision, but rather that its half life is, say, 90 days.

    Starting from these considerations, the basic function could be as simple as that:

    sub remaining { my ($start, $half, $elapsed) = @_; $remain = $start * (.5**($elapsed/half)); return $remain; }
    where $start is the starting quantity (in any unit), $half the half-life and $elapsed the period duration ($half and $elapsed just have to be expressed with the same unit). The function returns the quantity of substance remaining once the period has elapsed. A sample run could be this:
    print remaining (1000, 10, $_), "\n" for qw (10, 20, 30, 40); 500 250 125 62.5
    which, for an initial quantity of 1000 something (grams, kilograms or whatever) and a half-life of 10 time units and periods of 10, 20, 30, 40 of the same time unit, prints the remaining quantity for each of the four time periods. So, this is quite simple. You might want to add a check that the half-life argument is not 0 (to avoid a division by zero error) and other bells and whistles, but you basically have it.

    You almost never have to do time unit conversions with half-lives because of the exponential nature of the radioactive decay law. For example, if you have a half-life of one day, it makes very little sense to try to figure out what the remaining quantity is after one year, because it is so small:

    print remaining (1000, 1, 365), "\n"; 1.33061245000255e-107
    It is highly likely that there is not even one radioactive atom left after one year, even if your original quantity was tons of something (to give an idea of the magnitude of the numbers involved, one metric ton of for example carbon is "only" about 5e28 atoms).

Re: Simple algebraic calculations
by soonix (Canon) on Apr 19, 2014 at 03:40 UTC
Re: Simple algebraic calculations
by NetWallah (Canon) on Apr 18, 2014 at 22:51 UTC
    Would a general purpose website like http://www.wolframalpha.com help ? It understands Half life.

            What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?
                  -Larry Wall, 1992

Re: Simple algebraic calculations
by flexvault (Monsignor) on Apr 19, 2014 at 15:05 UTC

    Hello wanna_code_perl,

    Just a thought: Why not build your own Calculator?

    Back in the '80s I used 'C' to build a calculator for common things I needed for system administration activities. Each time I'd be called upon to change/fix/... a different system (mostly AIX systems), I would port my calculator to the new system. This had lots of problems since the 'C' compilers were always changing and not always available, but all the systems had Perl. So after becoming more familiar with Perl, I slowly ported each calculator function into a small script I called 'calc.plx' that used the standard system Perl, which called itself to do the calculations as a long one liner.

    The script grew to about 700 lines, and with a lot of comments, but it does exactly what I need it to do. and far exceeds what I could have done with the original 'C' calculator.

    Since you are writing one-liners anyway, why not copy them into your 'calc.plx' and build a way to call them. You will be amazed at how much fun adding functions can get once you have your own foundation script.

    Good Luck...Ed

    "Well done is better than well said." - Benjamin Franklin

Re: Simple algebraic calculations
by Laurent_R (Canon) on Apr 18, 2014 at 21:29 UTC
    There may be an existing module to do that, I haven't checked, and I would be a bit surprised that it did not exist, but if not, it should be quite easy to write one, this is really quite easy math to compute half life calculations. Once you have done that, you just need to call the module functions. I am not a nuclear scientist, but I think I know enough about these things to be able to come up with a module skeleton to implement at least the basic calculations. If nothing exists, I would be happy to take this as a challenge, Please ask if nothing exists.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (2)
As of 2024-03-19 06:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found