Invalid procedure call or argument - overflow? (2 Viewers)

Bob

Registered User.
Local time
Today, 22:56
Joined
Nov 15, 2009
Messages
19
Hi
Currently writing code for a financial function to calculate Internal Rate of Return for a series of payments and associated dates.
Code works well in most case, but will occasionally give me an error namely "Invalid procedure call or argument".

This is the code gives an error:
dblRate ^ dblTimeInvested
Values for the variables (declared as Double) are:
-16924727597.1152 and 2.28767123287671
Interestingly, if I enter those values in the Immediate Window, the calculation proceeds without an error.

I need to either use other variable types, or check values are within certain parameters.
Any ideas on how to proceed?

P.S. Also tried automating Excel and using XIRR worksheet function, but that gave other problems.
 
what is the data type of the variable you are assigning the result? double also?

the Initial (first value) to pass to your IRR function should be of Zero (no income yet) or Negative value (initial investment you put to the business).
 
Last edited:
Not sure if this helps, but I rolled my own XIRR functions. You can look at these. From others using it, they say it works.
Here is some discussion on the wrapper and home grown function.
see code in thread 16
 
Last edited:
FYI,
"Invalid procedure call or argument".
VBA can give some non-intuitive or even incorrect error messages. But that message does not seem to be anywhere even close to do with data types. You will likely need to provide more code for us to take a guess.
 
from chatgpt:
Code:
Function IRR(CashFlows As Variant, Optional Guess As Double = 0.1) As Double
    Dim MaxIterations As Integer
    Dim Iteration As Integer
    Dim Rate As Double
    Dim NPV As Double
    Dim Derivative As Double
    Dim Epsilon As Double
    Dim CashFlowSum As Double
    
    MaxIterations = 100
    Epsilon = 0.0001 ' The acceptable error in the result
    Rate = Guess ' Initial guess for the rate
    Iteration = 0
    
    ' Loop until we find the rate that brings the NPV close to zero
    Do
        NPV = 0
        Derivative = 0
        CashFlowSum = 0
        
        ' Calculate NPV and its derivative for the current rate
        For i = LBound(CashFlows) To UBound(CashFlows)
            CashFlowSum = CashFlowSum + CashFlows(i) / (1 + Rate) ^ i
            Derivative = Derivative - i * CashFlows(i) / (1 + Rate) ^ (i + 1)
        Next i
        
        NPV = CashFlowSum
        
        ' Check if the NPV is close enough to 0
        If Abs(NPV) < Epsilon Then
            IRR = Rate
            Exit Function
        End If
        
        ' Adjust the rate using Newton's method (estimate improvement)
        Rate = Rate - NPV / Derivative
        
        Iteration = Iteration + 1
        
        ' If the iteration limit is reached, exit the loop
        If Iteration > MaxIterations Then
            MsgBox "Max iterations reached"
            IRR = Rate
            Exit Function
        End If
    Loop
End Function
 
from chatgpt:
From a real person.
  • Proven, tested
  • designed to work directly in a query
  • With examples of use in Access
 
You will likely need to provide more code for us to take a guess.
I can fully reproduce the issue with the information provided:
Code:
Public Sub TestDoubleOverflow()

    Const dblRate As Double = -16924727597.1152
    Const dblTimeInvested As Double = 2.28767123287671
    
    Dim result As Double
    result = dblRate ^ dblTimeInvested

End Sub
 
From a real person.
does it conform to what microsoft said:

it need At Least 1 negative value.
the OP might not be having a negative value (or 0) on the start his data.
 
I can fully reproduce the issue with the information provided:
Code:
Public Sub TestDoubleOverflow()

    Const dblRate As Double = -16924727597.1152
    Const dblTimeInvested As Double = 2.28767123287671
 
    Dim result As Double
    result = dblRate ^ dblTimeInvested

End Sub
Stand corrected.
 
I also tested a bit in the Immediate Window.

These work fine:

Code:
Debug.Print -16924727597.1152 ^ 2.28767123287671

Debug.Print -16924727597.1152# ^ 2.28767123287671#

These not:

Code:
Debug.Print CDbl(-16924727597.1152) ^ CDbl(2.28767123287671)

Debug.Print (-16924727597.1152#) ^ (2.28767123287671#)

Debug.Print (-16924727597.1152) ^ (2.28767123287671)
 
does it conform to what microsoft said:

it need At Least 1 negative value.
the OP might not be having a negative value (or 0) on the start his data.
No it actually performs a check unlike MS and the function provided
Code:
If Not HasInvestment Then
    AccessXIRR = "All Positive Cash Flows"
  ElseIf Not HasPayment Then
    AccessXIRR = "All Negative Cash Flows"
  Else
 
SHORT ANSWER: Exponentiation of any non-zero power of a negative base is a disallowed function.

LONG ANSWER: From a strictly theoretical viewpoint, this problem depends on exactly how the exponentiation operator is defined for VBA. There are three possible interpretations to having a negative base and a fractional exponent. (By the end of this examination, I'll tell you which one VBA uses based on the findings.) See also this linked article:


I'm going to summarize:

For complex number exponentiation (involving SQR(-1) or "i" in math / "j" in physics 'cause "i" was already taken for current), then the answer is likely to be multi-valued with simultaneous positive and negative components for the real and complex parts. FORTRAN is an example of a programming language that DOES handle complex numbers. But VBA doesn't directly support complex numbers (it has no complex data type) so that certainly wouldn't apply to this case.

For discrete exponentiation, the subject situation is allowed in some cases, but the problem is that it is allowed only for specific values of the exponent, analogous if not identical in behavior to quantized entities in atomic and nuclear physics. I.e. only certain powers allow a solution and for other powers, there is no solution. This case is almost certainly not a discrete-exponentiation operation. One dead give-away is to look at the number of decimal places expressed in the exponent. Discrete, this is not. Which leaves us...

For CONTINUOUS exponentiation, which is the most common case and the one I believe is used by VBA (though the language manual doesn't say so explicitly), a fractional power of a negative base is undefined. That condition is probably the source of the "invalid procedure call" error.

From the VBA Language spec v04242014, section 5.6.9.3.7, ^ Operator,

If the left operand is 0 and the right operand is negative, runtime error 5 (Invalid procedure call or argument) is raised.

Here's how you get to that point:

First, it is a given fact purely based on observation that the exponent AND the negative base are both non-integers.
Second, considering the alternatives, it seems clear that this would have to be evaluated by the rules of continuous exponentiation. (This is a guess since Access is not OpenSource.)
Third, remember that no computer has a hardware exponentiation instruction. All computers perform exponentiation by software functions.

To software-evaluate this general expression:

x = -a^b

(where a and b are both real (but non-integer) numbers and in this case, a is positive so -a is negative), a computer will try to evaluate

x = EXP( b * LN( -a ) )

(where EXP is exponentiation base e and LN is natural logarithm (also base e), and e is Euler's constant, equal to 2.718281828459045... (approximately).

The problem immediately crops up on the LN function, for which there IS no logarithm for a negative number, integer or non-integer. The operation to derive the logarithm of a negative number is undefined.

Since the operator is implemented by an internal function, it breaks it down to steps. The odds are that in either SQL or VBA, the step that attempts to resolve LN( -a ) will return zero, which then leads directly to the stated error condition that occurs when raising zero to a fractional power.

Note, however, that there is an order of execution issue: Exponentiation occurs before unary negation. Therefore, the fact that you can get an answer at all for the original expression implies that you are actually evaluating:

x = -( EXP( b * LN( a ) ) ) = - (a^b)

That is, because of operator precedence, that pesky minus-sign on a is deferred until after the exponentiation occurs.

@AHeyne performed testing that showed that adding explicit parentheses, which overrides default math operator order, forces the unary negation to occur BEFORE the exponentiation, and that will not work. You will get an error 5, Invalid Procedure Call. I verified that myself using the immediate window, too, just to be sure the issue wasn't version-specific - and it isn't specific.

@sonic8 took a different approach and loaded the values to variables. But in so doing, he applied the unary negation to the variable BEFORE the exponentiation could occur, and so exhibited the same problem.

This is a round-about way of suggesting that VBA uses continuous exponentiation, which is important in this context because it means that negative bases are not normally allowed. The same error will occur any time you write the expression in such a way that you apply the unary minus sign BEFORE you apply the exponentiation operator.

By the way, if you evaluate that expression in a way to avoid the error trap, you end up with a number that is roughly 2.somethingE+23, or over 200 sextillion when using USA number-naming. That is a very large number. If that is a potential return on investment, sign me up, please.
 
the OP on the different thread did not say anything that it works.
you just assumed it did.
Really? It kind of sounds to me like the author had been using it with success and was pretty pleased with it.
I have been using the great AccessXIRR function since a while. It has been working perfectly except for one case, for which Excel XIRR returns a value.
Besides calling it Great and working perfectly for a while except for one case, which I then go into detail to discuss.
Where again am I making an assumption that it was working? Please enlighten me.
 
Really? It kind of sounds to me like the author had been using it with success and was pretty pleased with it.
i never see anything like that on the thread, not a single clue. while on your part, lots of doubt on your own code.
 
I can fully reproduce the issue with the information provided:
That is not really my point. My point is how can the OP get those values unless the OP's code is jacked up. So without seeing the code reproducing the problem with non-sensical data does not really get you far.

Because what the OP shows is illogical, it is not a question why it errors the question is how the OPs codes is running away and generating those values.

In the XIRR code there are several places that you calculate

(1+Rate)^(TimeInvested)
or
(1+Rate)^(Time Invested + 1)

However the rate is being updated in a loop as the Net Present Value approaches 0.
The GPT version is simplistic and assumes you are doing each month and therefore the time is simply i. I calculate the real time invested so the payments can be unequal or greater/less than a month.
Rates are realistically between 0 and 1. However as the solution iterates the rates start off very negative and then start converging as you iterate the cash flow.
But getting values about a billion order a magnitude from what you expect is problematic.

As @arnelgp stated the problem has to be formulated correctly.
You need at least one (-) investment and at least one (+) payment.
The payment periods need to be consecutive (increasing dates) and equal the number of investments and payments.
If you do not formulate correctly, I guess you could get a runaway condition.

In the function the rate is being continually recalculated. In all versions of the XIRR that use the newtons method to find where the NPV is 0 you have a tolerance and have a counter so that the function ends when it converges close to zero and kicks out if it is not converging.

However even if it does not converge I do not think it starts expanding uncontrollably. I think it will oscillate within reasonable boundaries.
I like the OP to provide the cashflow to test.

It is possible that the XIRR will never converge, but I do not think if it is coded correctly and a properly formed Payments and Dates that you could ever generate a value that the OP shows.

I did notice that I did have the checks in my function but only if being called from access. So I incorporate the checks for a proper formatted problem
+ and - cashflows
equal payments and dates
Consecutive dates

Remember the XIRR is used for comparisons of alternatives. So a lot of nonsensical cashflows do not even make sense to analyze and likely will not converge. You are unlikely to take an opportunity where you can clearly see that the investment well exceeds the payments. So I think a lot of the negative rates of return will not solve.

Here is an update with some checks I added to make sure it is properly formatted problem

Code:
 'Validate Dates and Payments are synched
   If UBound(Payments) <> UBound(Dates) Then
     MsgBox "Must have equal Number of payments and Dates.", vbCritical, "Equal Payments and Dates"
     Exit Function
   End If
 
   'Validate Consecutive dates
   For i = 0 To UBound(Dates)
     If i = 0 Then
       PreviousDate = Dates(i)
     Else
       If Dates(i) <= PreviousDate Then
          MsgBox "Dates must be Consecutive. Validate your dates are in order and equal number of payments/investments", vbCritical, "Consecutive Dates"
          Exit Function
       Else
          PreviousDate = Dates(i)
       End If
     End If
   Next i
 
 
   'Validate cash flow is proper. Need both (-) investments and (+) payments
   For i = 0 To UBound(Payments)
     If Payments(i) > 0 Then HasPayment = True
     If Payments(i) < 0 Then HasInvestment = True
     If Payments(i) = 0 Then
        MsgBox "Invalid Cashflow value equal 0", vbCritical, "Investment or Payment = 0"
     End If
   Next i
   If Not HasPayment Or Not HasInvestment Then
       MsgBox "Invalid Cash flow.  Must have at least one negative investment and one postive payment", vbCritical, "Invalid Cash Flow"
       Exit Function
   End If
 

Attachments

Last edited:
i never see anything like that on the thread, not a single clue
I am sorry can you not read english?
Maybe this helps.
dh.PNG


Just give it a break. WTF is your issue???
How about test it against some different cash flows and run it against the Excel XIRR. I have done that with lots of cases and get the same in most cases and solve cases that Excel does not. In some cases does not solve where Excel does. But as pointed out there are times it may or may not solve a cash flow. But this is the same in Excel as well.

I do not what you problem is, but if you think it does not work then provide something better.
Another thing I provide is that basis to generate a GoodGuess based on the cash flow.
If you want to talk off line hit me up, because now you are just being a pain in the ass.
 
the code given earlier from chatGPT is simple irr from Regular Interval cashflow.
another version of chatGPT for payment with dates is provided. not tested yet.

Code:
Function IRRWithDates(Values() As Double, Dates() As Date, Optional Guess As Double = 0.1) As Double
    Dim MaxIter As Integer, Tolerance As Double
    Dim Iteration As Integer
    Dim X0 As Double, X1 As Double
    Dim NPV As Double, Derivative As Double
    Dim i As Integer
   
    MaxIter = 1000 ' Maximum iterations for Newton-Raphson method
    Tolerance = 0.0000001 ' Convergence tolerance
    X0 = Guess ' Initial guess for IRR

    For Iteration = 1 To MaxIter
        NPV = 0
        Derivative = 0
       
        ' Calculate NPV and its derivative with respect to IRR
        For i = LBound(Values) To UBound(Values)
            Dim TimeDiff As Double
            TimeDiff = (Dates(i) - Dates(0)) / 365 ' Time difference in years
            NPV = NPV + Values(i) / (1 + X0) ^ TimeDiff
            Derivative = Derivative - TimeDiff * Values(i) / (1 + X0) ^ (TimeDiff + 1)
        Next i

        ' Update guess using Newton-Raphson
        X1 = X0 - NPV / Derivative

        ' Check for convergence
        If Abs(X1 - X0) < Tolerance Then
            IRRWithDates = X1
            Exit Function
        End If

        X0 = X1
    Next Iteration

    ' If no convergence, return an error
    Err.Raise vbObjectError + 513, "IRRWithDates", "IRR calculation did not converge."
End Function

can be easily converted to handle recordset from table.
 
Great! So what? If you think it is better for some reason then have at it. I already provided a solution for access, provided formatting checks, provide initial guess, but if somehow this is better then knock yourself out.
 

Users who are viewing this thread

Back
Top Bottom