Re: Self-teaching snag
- To: mathgroup at smc.vnet.net
- Subject: [mg74573] Re: Self-teaching snag
- From: Jean-Marc Gulliet <jeanmarc.gulliet at gmail.com>
- Date: Tue, 27 Mar 2007 03:55:28 -0500 (EST)
- Organization: The Open University, Milton Keynes, UK
- References: <eu7re0$b6p$1@smc.vnet.net>
Todd Allen wrote: [snip] > Here is the scenario: I have written a basic function > to tell me what percentage of battery power will > remain in a battery after x number of days, provided > that we start with a full charge and lose 5% of that > charge per day. > > If you execute the following code in Mathematica > (V5.1): > > charge[0]=1.0 (* 100% *); > charge[day_]:=(charge[day-1]-(0.05*charge[day-1])); > charge[20] > > I receive an output of 0.358486 for my query at the 20 > day mark.....so, no problem so far. You already have a major issue with the general recurrence relation. Basically, what you have defined is a double recurrence (like Fibonacci's numbers, but here the double recurrence is not needed. See below.) and the computational time grow exponentially. Say you want the charge of the battery after 3 days. To compute charge[3], you must compute charge[2] twice. To compute charge[2], you must compute charge[1] twice. To compute charge[1], you must compute charge[0] twice. Therefore, to compute charge[3], you must compute charge[2] twice, charge[1] four times, and charge[0] eight times. You ask Mathematica to do 2 + 4 + 8 == 2^1 + 2^2 + 2^3 == 14 computations. (Here computation is synonymous of function call, overlooking details such as retrieving values, adding and multiplying them, and memory consumption.) Without proving it formally (proof by induction), the relationship between the number of computations and the number of days (starting at 1) is of the form Sum[2^i, {i, n}]. Let's check, with the help of Mathematica, how many computations are required for some number of days. c[n_] := Sum[2^i, {i, n}] Table[c[n], {n, 1, 10}] {2, 6, 14, 30, 62, 126, 254, 510, 1022, 2046} To get the value of the charge of the battery after 20 days, you must compute c[20] == 2097150 (over 2 millions of computation), and to get the value after 35 days, Mathematica must compute c[35] == 68719476734 (nearly 70 billions of computations). No wonder it might takes some time to Mathematica to return an answer. > However, when I try to ask for the output at > charge[35], mathematica seems to enter an endless > calculation. I've let the computer run for as long as > 5 minutes without getting an answer. Is there > something wrong with my function, my version of > Mathematica or something else I haven't considered? Now, let's improve the code. As stated previously, you do not need a double recursion, since the charge of the battery as of today, say, is 95% of the charge of the battery of yesterday. (This is equivalent to charge of the battery of yesterday minus 5% of charge of battery of yesterday.) Now, compare your original code against this simplified formula: In[1]:= Clear[charge]; charge[0] = 1.; charge[day_Integer] := charge[day - 1] - 0.05*charge[day - 1]; Timing[charge[20]] Out[4]= {5.485 Second, 0.358486} In[5]:= Clear[charge]; charge[0] = 1.; charge[day_Integer] := 0.95*charge[day - 1]; Timing[charge[20]] Out[8]= {0. Second, 0.358486} We can even improve the performances, although this is not noticeable here, by using the technique described in section 2.5.9 of The Mathematica Book [1]. Note that it is easy to plot the values of the charge against the number of days and to check that the relationship is a decaying exponential, indeed. In[9]:= Clear[charge]; charge[0] = 1.; charge[day_] := charge[day] = 0.95*charge[day - 1]; Timing[charge[50]] ListPlot[Table[charge[n], {n, 0, 50}]]; Out[12]= {0. Second, 0.076945} [...graphic deleted...] > Additionally, > > When I try the following: > > In[145]:= > Solve[charge[day]==0.15,day]; > > Mathematica gives me the error: > "$RecursionLimit::reclim: Recursion depth of 256 > exceeded." > > I am trying to ask Mathematica to tell my how many > days it takes to reduce the battery power to 15 > percent, but I must be messing something up?? [snip] To get an answer, you can use a plot, or an interpolating function, or solve the following initial-value problem (first-order differential equation of an exponential decay). In[14]:= Clear[charge]; eqn = Derivative[1][charge][t] == (-5/100)*charge[t]; iv = charge[0] == 1; sol = DSolve[eqn && iv, charge, t] Plot[charge[t] /. sol[[1]], {t, 0, 50}]; Out[17]= -t/20 {{charge -> Function[{t}, E ]}} [...graphic deleted...] In[19]:= Solve[(charge[t] /. sol[[1]]) == 0.15, t] Solve::ifun: Inverse functions are being used by Solve, so some solutions may not be found; use Reduce for complete solution information. More... (* You can disregard the warning message above. *) Out[19]= {{t -> 37.9424}} In[20]:= charge[t] /. sol[[1]] /. %[[1]] Out[20]= 0.15 In[21]:= Reduce[(charge[t] /. sol[[1]]) == 15/100, t, Reals] Out[21]= 20 t == 20 Log[--] 3 In[22]:= N[%] Out[22]= t == 37.9424 Regards, Jean-Marc [1] "2.5.9 Functions That Remember Values They Have Found" http://documents.wolfram.com/mathematica/book/section-2.5.9