Friday Puzzler: Show me the money

Today's Friday Puzzler (it's been a while - sorry!) is from LessThanDot: How many days before I double my money. Their problem was: Given 1000 dollars and 1% interest every day - now long until you double your money. Since ColdFusion makes everything simpler, I'm going to make this a bit more complex. Your challenge is to write a generic UDF that:

  • Takes in an initial balance
  • Takes in a percentage interest value
  • Takes in a desired total

Given the parameters above, your UDF will return how many days it takes to go from the initial balance to the total. If you want - just write the UDF. If you're bored - write a program that will chart out the balance growth every day.

Want some incentive? The best entry will get a 20 dollar gift certificate. "Best" will be 100% subjective and probably unfair.


Archived Comments

Comment 1 by Adam Tuttle posted on 9/10/2010 at 4:40 PM

numeric function getPeriods(required numeric initBalance, required numeric intRate, required numeric desiredTotal) output="false" {
//assume interest rate is of format .5 = 50%
var periods = (log(arguments.desiredTotal) - log(arguments.initBalance))/log(1+arguments.intRate);
return (ceiling(periods));
}

Comment 2 by Amar posted on 9/10/2010 at 4:41 PM

function calculatedays(x,y,z)
{ // x = amount, y= percent interest, z=desired amount
var days = 0;
var w = x;
while (w<z)
{w=w+(w*y/100);
days=days+1;
}
return days;
}

Comment 3 by Adam Tuttle posted on 9/10/2010 at 4:41 PM

Or to see it with some proper formatting: http://gist.github.com/573566

Comment 4 by Danny posted on 9/10/2010 at 4:58 PM

<cffunction name="daysTill" returntype="struct">
<cfargument name="initBal" type="numeric" required="true">
<cfargument name="interVal" type="numeric" required="true" hint="Interest Value as percent">
<cfargument name="desireTotal" type="numeric" required="false" default="#arguments.initBal*2#">
<cfargument name="returnChart" type="boolean" required="false" default="false">

<cfset var dayCount = 0/>
<cfset var currentAmount = arguments.initBal/>
<cfset var chartQuery = querynew("day,currentamount")/>
<cfset var outStruct = {}/>
<cfset var theChart = ""/>

<cfloop condition="#currentAmount# LT #arguments.desireTotal#">
<cfset currentAmount += (currentAmount * (arguments.interVal/100))/>
<cfset daycount++/>
<cfset queryaddrow(chartQuery)/>
<cfset querysetcell(chartQuery,"day",NumberFormat(daycount))/>
<cfset querysetcell(chartQuery,"currentAmount",currentAmount)/>
</cfloop>
<cfset outStruct.days = daycount/>
<cfif arguments.returnChart>
<cfsavecontent variable="theChart">
<cfchart title="Growth at #arguments.interVal#% interest" chartheight="500" chartwidth="500" xaxistitle="Days" yaxistitle="Dollar Amount">
<cfchartseries query="chartQuery" itemcolumn="day" valuecolumn="currentAmount" type="line">
</cfchart>
</cfsavecontent>
<cfset outStruct.theChart = theChart/>
</cfif>
<cfreturn outStruct/>
</cffunction>

Comment 5 by Jeff Price posted on 9/10/2010 at 5:29 PM

function calculatedays(amount,rate,total)
{
return 42;
}

My answer is correct, I believe it is your question that is wrong.

Comment 6 by Raymond Camden posted on 9/10/2010 at 5:31 PM

Ok, I got to say - even with Adam's being the shortest, I think Jeff may win just cuz. ;)

Comment 7 by Louis posted on 9/10/2010 at 5:33 PM

<cffunction name="calculate_interest">
<cfargument name="balance" type="numeric" required="yes">
<cfargument name="interest" type="numeric" required="yes">
<cfargument name="desired" type="numeric" required="yes">

<cfset var i = 0>
<cfset var total = arguments.balance>

<cfloop condition="total lt arguments.desired">
<cfset i = i + 1>
<cfset daily_interest = (total / 100) * arguments.interest>
<cfset total = total + daily_interest>
</cfloop>

<cfreturn i>
</cffunction>

<cfoutput>#calculate_interest(1000, 1, 2000)#</cfoutput>

Comment 8 by Louis posted on 9/10/2010 at 5:39 PM

Although mathematically Adam's entry is the best, I feel it fails as it doesn't meet this requirement:

* Takes in a percentage interest value.

As I always say, if you can't win by being the most talented, find a technicality and get the opposition disqualified :P

Comment 9 by Justin Mclean posted on 9/10/2010 at 5:48 PM

How about some unnecessary recession? If you get a stack overflow it's going take too long and you should invest elsewhere :-)

<cfscript>
function calculateDays(initalAmount,finalAmount,rate)
{
newAmount = initalAmount*(1+rate/100);

if (ArrayLen(arguments) gt 3) {
days = arguments[4];
}
else {
days = 1;
}

if (newAmount <= finalAmount) {
return calculateDays(newAmount,finalAmount,rate,days+1);
}
else {
return days;
}
}
</cfscript>

<cfdump var="#calculateDays(1000,2000,1)#">

Comment 10 by Justin Mclean posted on 9/10/2010 at 6:05 PM

Opps. Recursion even.

Comment 11 by Don posted on 9/10/2010 at 6:18 PM

function db(p1,p2,i){
return ceiling(log(p2/p1)/(log(1+i/(365*100))));
}

Comment 12 by Raymond Camden posted on 9/10/2010 at 6:19 PM

jeeze Don - thats fricken short!

Comment 13 by Mark Andrachek posted on 9/10/2010 at 6:58 PM

<cffunction name="getN" hint="Get the number of periods it will take to reach your investment.">
<cfargument name="P" type="numeric" hint="The present value."/>
<cfargument name="i" type="numeric" hint="The interest rate in percent."/>
<cfargument name="F" type="numeric" hint="The goal, the final value."/>
<!--- N = ln(F/P)/ln(1+i) --->
<cfreturn log(arguments.F/arguments.P)/log(1+(arguments.i/100)) />
</cffunction>

Comment 14 by Curt Gratz posted on 9/10/2010 at 7:01 PM

Everyone is forgetting to take into account the current President. This makes a very LARGE difference in this calculation.
<cfscript>
function calculateDays(amount,percent,endingAmount,currentPres){
var daysToTotal = 0;
var workingAmount = amount;

while (workingAmount<endingAmount) {
workingAmount=workingAmount+(workingAmount*percent/100);
daysToTotal=daysToTotal+1;
}

//if we are under the Obama administration, add 5 more days
if (structKeyExists(arguments,"currentPres") and len(currentPres) and currentPres contains "Obama"){
daysToTotal=daysToTotal+5;
}
//if we are under the Bush administration, add 3 more days
else if (structKeyExists(arguments,"currentPres") and len(currentPres) and currentPres contains "Bush"){
daysToTotal=daysToTotal+3;
}
//if we are under the Reagan administration, add 50 more days
else if (structKeyExists(arguments,"currentPres") and len(currentPres) and currentPres contains "Cliton"){
daysToTotal=daysToTotal+50;
}
//if we are under the Reagan administration, subtract 25 days
else if (structKeyExists(arguments,"currentPres") and len(currentPres) and currentPres contains "Reagan"){
daysToTotal=daysToTotal-25;
}

return daysToTotal;
}
</cfscript>
<cfoutput>#calculateDays(1000,1,5000)#</cfoutput>
<cfoutput>#calculateDays(1000,1,5000,"Barack Obama")#</cfoutput>
<cfoutput>#calculateDays(1000,1,5000,"George W. Bush")#</cfoutput>
<cfoutput>#calculateDays(1000,1,5000,"Bill Cliton")#</cfoutput>
<cfoutput>#calculateDays(1000,1,5000,"George Bush Senior")#</cfoutput>
<cfoutput>#calculateDays(1000,1,5000,"Ronald Reagan")#</cfoutput>

Comment 15 by Raymond Camden posted on 9/10/2010 at 7:02 PM

Truly sad there Curt. ;)

Comment 16 by sue lornitzo posted on 9/10/2010 at 7:17 PM

<!---A=desired amount
R=desired rate
t=time in years
p=initial amount

Submitted by Sue Lornitzo
Lornitzo@charter.net--->

<cfif isDefined('calculate') is 'YES'>
<cfset top=log(#A#/#P#)>
<cfset R=#R#/100>
<cfset bottom=log(1+#R#)>
<cfset fractionTop=#top#/#bottom#>
<cfset multiplier=#fractionTop#/365>
<cfset t=365*#multiplier#>

<center>
<cfoutput>
<br>
<br>
<cfset DesiredRate=#R#*100>
<p style="color:maroon;">You will reach your goal of #dollarFormat(A)#, at #DesiredRate#% per day, in #decimalFormat(t)# days</p>
</cfoutput>

<br>
<br>

<cfset x_max=#t#+2>

<cfset y_max=#t#+2>
<cfset y_min=#P#*.8>

<cfchart
format="png"
scalefrom="#y_min#"
scaleto="#y_max#"
xAxisTitle = "Days"
yAxisTitle = "Amount" >
<cfchartseries
type="line"
serieslabel="Website Traffic 2006"
seriescolor="blue"
>

<cfset x_max=#t#+2>
<cfloop from="1" to="#x_max#" index="i">

<cfset currentAmt=(#P#*(1+#R#)^(#i#))>
<cfchartdata item="#i#" value="#currentAmt#">
</cfloop>
</cfchartseries>
</cfchart>

<br>
</cfif>

<br>
<br>
<p style="font-size:.7em;color:blue;text-align:center;">*Disclaimer:I did this in a hurry so formatting is a bit weak ): <br>
Sue Lornitzo<br>
Lornitzo@charter.net</p>
<form name="InvestmentCalculator" method="post" style="width:800px;">
<fieldset style="border:1px solid gray;padding-left:2em;padding-right:2em;">
<legend style="padding-bottom:3em;">
When will You Be Rich??
</legend>
<p>

<label for="initialAmt" class="required" style="width: 12em;float:left;text-align: right;margin-right:2em;display:block;">Initial Investment Amount</label>

$<input type="text" name="P" required="no" style="width:12em;border:1px solid black;width:12em;">

</p>
<br>
<p>

<label for="dailyInterestRate" class="required" style="width: 12em;float:left;text-align: right;margin-right:2em;display:block;" >Daily Interest Rate (Less than 100%)</label>

<input type="text" name="R" required="yes" style="width:12em;border:1px solid black;width:3em;">%
</p>
<br>
<p>

<label for="DesiredAmt" class="required" style="width: 12em;float:left;text-align: right;margin-right:2em;display:block;" >Enter amount you would like to reach</label>

$<input type="text" name="A" required="yes" style="width:12em;border:1px solid black;width:12em;">
</p>
<br>
<p>
<input type="submit" name="calculate" value="Calculate">

</p>

</fieldset>

</form>

Comment 17 by Gary Funk posted on 9/10/2010 at 7:35 PM

Don's code is a little off. It should be

ceiling(log(p2/p1)/(log(1+(1/100))))

Comment 18 by Raymond Camden posted on 9/10/2010 at 7:52 PM

I think the winner should be the code that a) works and b) uses the most parenthesis.

Comment 19 by John Luopa posted on 9/10/2010 at 8:04 PM

<cffunction name="getHowManyDaysToSave" returntype="numeric" access="public">
<cfargument name="initialBalance" type="numeric" required="true">
<cfargument name="percentageInterest" type="numeric" required="true">
<cfargument name="desiredTotal" type="numeric" required="true">

<cfset local.numberOfDays = 0>
<cfset local.currentTotal = arguments.initialBalance>

<cfloop condition="local.currentTotal LESS THAN OR EQUAL TO arguments.desiredTotal">
<cfset local.currentTotal = local.currentTotal + (local.currentTotal * (arguments.percentageInterest / 100))>
<cfset local.numberOfDays = local.numberOfDays + 1>
</cfloop>
<cfreturn local.numberOfDays>
</cffunction>

Comment 20 by Susan Brun posted on 9/10/2010 at 9:32 PM

<cffunction name="getDays" returntype="Numeric">
<cfargument name="PresentValue" type="numeric">
<cfargument name="FutureValue" type="numeric">
<cfargument name="interestPercentage" type="Numeric">

<cfset numberOfPeriods = (log(#arguments.FutureValue#) - log(#arguments.PresentValue#))/log(1+(#arguments.interestPercentage#/100))>

<cfreturn numberOfPeriods>

</cffunction>

<cfoutput>#getDays(1000,2000,1)#</cfoutput>

Comment 21 by Raymond Camden posted on 9/10/2010 at 11:01 PM

It's almost that time - isn't it. So let me ask the people who subscribed when posting comments - which do YOU think is the best? :)

Comment 22 by Raymond Camden posted on 9/11/2010 at 12:44 AM

Ok, it was a toss up between Don's, which was sooooo short, and Danny's. I took one point off on Don's code since it was broken (Gary's comment fixed it), and I gave Danny a point for making use of cfsavecontent to wrap the chart. Kinda cool. Although I woulda been more happier if he had used name="theChart" to actually store the binary - this was easier to use. :)

So thank you all - Danny gets to be the winner today. Danny, ping me via email and I'll drop off your Amazon gift cert.

Comment 23 by Don Vawter posted on 9/11/2010 at 12:48 AM

@Gary it depends whether i is the annual percentage rate (which I assume). If you leave out the 365 then the interest rate provided would need to be the daily interest rate.

Comment 24 by Jetherson Arceo posted on 9/13/2010 at 8:18 PM

Shouldn't those 365's be 365.25?
:)

Comment 25 by Gary Funk posted on 9/13/2010 at 9:31 PM

@Dan. That is true and that is the answer you gave. However, that is not the question that Ray asked.

Comment 26 by Don Vawter posted on 9/13/2010 at 10:20 PM

@Gary. The question posed states "interest rate" and is silent on whether that is an annual percentage rate or daily. If I could figure out how to earn 1% daily on a safe investment I would retire.

Comment 27 by Gary Funk posted on 9/13/2010 at 11:33 PM

He stated 1% interest every day. He didn't say it was 1% anually compounded daily.

Comment 28 by Gary Funk posted on 9/13/2010 at 11:34 PM

Part of being a great programmer is knowing what your customer is really asking for.