上一版实现:https://www.cnblogs.com/Alex-Zeng/p/9334582.html
上一版实现在某些情况下会计算出负值,与Excel的计算有差异。所以修改了实现方法。
实现的具体代码如下:
function IRR_ZEN(p_amount_array in typ_cashflow_array) RETURN NUMBER is rtn_err number := 0; irrGuess number := 0.01; -- default: 10% irr number := 0.0; minDistance number := 1E-15; --iteration: the smaller the distance, the smaller the interpolation maxIteration integer := 1000; wasHi boolean := false; noOfCashFlows integer := 0; cashValue number := 0.0; cashFlowStart number := 0.0; result_value number := 0.0; BEGIN irr := irrGuess; result_value := -999999; noOfCashFlows := p_amount_array.count; -- business startup costs cashFlowStart := p_amount_array(1); for i in 1 .. maxIteration loop -- calculate cash value with current irr: cashValue := cashFlowStart; -- init with startup costs -- for each cash flow for j in 2 .. noOfCashFlows loop cashValue := cashValue + p_amount_array(j) / power(1.0 + irr, j-1); end loop; -- cash value is nearly zero if (abs(cashValue) < 0.0000000001) then -- dbms_output.put_line('abs(cashValue) < 0.0000000001 : '||to_char(cashValue)); result_value := irr; exit; end if; -- adjust irr for next iteration: -- cash value > 0 => next irr > current irr if (cashValue > 0) then if wasHi then irrGuess := irrGuess / 2; end if; irr := irr + irrGuess; if wasHi then irrGuess := irrGuess - minDistance; wasHi := false; end if; else -- cash value < 0 => next irr < current irr irrGuess := irrGuess / 2; irr := irr - irrGuess; wasHi := true; end if; -- estimated result too small to continue => end -- calculation if (irrGuess <= minDistance) then -- dbms_output.put_line('irrGuess <= minDistance : '||to_char(irrGuess)); result_value := irr; exit; end if; end loop; return result_value; EXCEPTION WHEN OTHERS THEN dbms_output.put_line(substr(sqlerrm, 1, 640)); return rtn_err; END IRR_ZEN;