Friday Puzzler: Show me the money

This post is more than 2 years old.

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.


Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

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.