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
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));
}
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;
}
Or to see it with some proper formatting: http://gist.github.com/573566
<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>
function calculatedays(amount,rate,total)
{
return 42;
}
My answer is correct, I believe it is your question that is wrong.
Ok, I got to say - even with Adam's being the shortest, I think Jeff may win just cuz. ;)
<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>
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
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)#">
Opps. Recursion even.
function db(p1,p2,i){
return ceiling(log(p2/p1)/(log(1+i/(365*100))));
}
jeeze Don - thats fricken short!
<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>
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>
Truly sad there Curt. ;)
<!---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>
Don's code is a little off. It should be
ceiling(log(p2/p1)/(log(1+(1/100))))
I think the winner should be the code that a) works and b) uses the most parenthesis.
<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>
<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>
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? :)
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.
@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.
Shouldn't those 365's be 365.25?
:)
@Dan. That is true and that is the answer you gave. However, that is not the question that Ray asked.
@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.
He stated 1% interest every day. He didn't say it was 1% anually compounded daily.
Part of being a great programmer is knowing what your customer is really asking for.