function amt_new=inflate(amt,year1,year2)
%INFLATE Adjust for inflation using the CPI Inflation Calc at BLS.gov.
%
% INFLATE(AMT,YEAR1,YEAR2) adjusts the value of the US dollar amount AMT
% for inflation as per the consumer price index, from what AMT was in year
% YEAR1 to what it was in year YEAR2. This is done using the CPI Inflation
% Calculator provided by the Bureau of Labor Statistics.
%
% AMT can be any dollar amount. YEAR1 and YEAR2 each can both be any year
% from 1913 to the current year. YEAR2 is optional, with its default value
% being the current year.
%
% EXAMPLES:
%
% inflate(100,1913,2007) returns 2055.5455
% This indicates that $100 in the year 1913 had the same purchasing
% power as $2,055.55 in the year 2007.
%
% inflate(100,2007,1913) returns 4.8649
% inflate(1,1975,2000) returns 3.2007
% inflate(10.00,2001) returns 11.4906
%
% amts=[100,10,1000];
% years1=[2000,1925,1950];
% years2=repmat(2007,size(amts));
% amts_new=arrayfun(@inflate,amts,years1,years2)
% returns [118.1760, 116.2851, 8443.9419]
%
% REMARKS:
%
% - Internet connectivity is required for this function to work.
% - This function will stop working if BLS changes its CPI Inflation
% Calculator page in a way that is sensitive to this function.
% - The URL to the CPI Inflation Calculator page is
% http://data.bls.gov/cgi-bin/cpicalc.pl
% - A "persistent" variable is used, so BLS is queried only once per
% session for every new combination of years.
% - It is of course possible to perform adjustment calculations
% entirely offline - this is warranted in any production environment.
% This is possible as long as historical CPI or inflation rates are
% available. By querying BLS, this function takes a somewhat lazy
% approach.
%
% VERSION: 20070703
% MATLAB VERSION: 7.4.0.287 (R2007a)
% LICENSE: As-is; public domain
%
% See also URLREAD, REGEXP.
%{
VERSION HISTORY:
20070703: - Added MATLAB version check.
20070410: - Shortened the displayed returned values in examples.
20070409: - Reorganized into subfunctions.
- Added persistent variable to lookup over same years faster.
- The output is no longer rounded to two decimal places.
20070401: - Made a minor update to an error message.
20070329: - Original version.
KEYWORDS:
inflation, deflation, CPI, BLS, consumer price index, inflation calculator
%}
%% Pseudocode
%{
Declare any needed input arguments
Validate all inputs
Handle trivial cases efficiently
Lookup normalized output in matrix
If normalized output not in matrix
Lookup normalized output on web
Update normalized output in matrix
Denormalize output
%}
%% Check MATLAB version
if datenum(version('-date'))<datenum('29-Jan-2007')
error(['The MATLAB version in use is ',version('-release'),'. ',...
'This function requires at least version 2007a.'])
end
%% Declare any needed input arguments
if nargin<2
help inflate
return
elseif nargin<3
year2=str2double(datestr(date,10));
end
%% Do some input validation
assert(all([isnumeric(amt) isnumeric(year1) isnumeric(year2)]),...
'All input arguments must be numeric.')
assert(all([numel(amt) numel(year1) numel(year2)]==1),...
'All input argments must be single numbers.')
assert(all([year1 year2]>=1913),...
'Both year1 and year2 must be at least 1913.')
assert(all([year1 year2]<=str2double(datestr(date,10))),...
'Neither year1 nor year2 must be greater than the current year.')
%% Handle trivial cases efficiently
if year1==year2 || amt==0
amt_new=amt;
return
end
%% Call lookup subfunction
amt_new=lookup(amt,year1,year2);
%% Subfunction: lookup
function[amt_new]=lookup(amt,year1,year2)
% Declare normalized amount
amt_normalized=10^7;
%{
Note that here the amount has been normalized to the largest input dollar
amount allowed by the Inflation Calculator. This is done in order to
allow for the maximization of the precision of the number of decimal
places of the output provided by the Inflation Calculator.
%}
% Declare persistent inf_rates variable, and conditionally initialize it
persistent inf_rates
years=str2double(datestr(date,10))-1913+1;
if isempty(inf_rates)
inf_rates=sparse(zeros(years));
elseif years>length(inf_rates)
inf_rates_old=inf_rates;
inf_rates=sparse(zeros(years));
inf_rates(1:length(inf_rates_old),1:length(inf_rates_old))=inf_rates_old;
clear inf_rates_old
end
% Lookup adjusted amount rate in matrix
amt_new=inf_rates(year1-1913+1,year2-1913+1);
% Lookup adjusted amount rate on web if relevant
if ~logical(amt_new)
amt_new=inflate_web(amt_normalized,year1,year2);
inf_rates(year1-1913+1,year2-1913+1)=amt_new;
inf_rates(year2-1913+1,year1-1913+1)=(amt_normalized^2)/amt_new;
end
% Denormalize adjusted amount rate to return output
amt_new=amt_new*(amt/amt_normalized);
%% Subfunction: web lookup
function[amt_new]=inflate_web(amt_normalized,year1,year2)
% Declare variables
url.url='http://data.bls.gov/cgi-bin/cpicalc.pl';
url.params={'cost1',num2str(amt_normalized),...
'year1',num2str(year1),'year2',num2str(year2)};
url.triesmax=5;
% Resiliently read URL
for tries=1:url.triesmax;
[url.page,url.readstatus]=urlread(url.url,'get',url.params);
if url.readstatus==1 && ...
~isempty(strfind(url.page,'<span id="answer">'))
break
end
if tries==url.triesmax
error(['There was an error reading ',url.url])
end
pause(tries*2)
end
clear tries
% Extract amount
amt_new=regexp(url.page,'<span id="answer">\$(?<val>.*)</span>','names');
amt_new=str2double(amt_new.val);