log of negative real numbers > RuntimeWarning: invalid value encountered in log
Why does numpy produce a runtime warning (invalid value encountered in log) when taking the log of a negative number? I noticed that if you coerce the argument to complex by adding 0j to the negative number, the expected result is produced (i.e. ln(1) = pi*i). I was surprised I couldn't find a discussion on this, as I would have expected others to have come across this before. Packages like Matlab handle negative numbers automatically by doing the complex conversion.
One explanation for this behavior is that doing otherwise would be slow.
Consider an array like
arr = np.array([1]*10**6 + [1])
ret = np.log(arr)
Today, what happens is:
 The output array is allocated as np.double
 The input array is iterated over, and log evaluated on each element in
turn
For what you describe to happen, the behavior would have to be either:
 The output array is allocated as np.double

The input array is iterated over, and log evaluated on each element in
turn

If any negative element is encountered, allocate a new array as
np.cdouble, copy all the data over, then continue. This results in the
whole array being promoted.
or:
 The input array is iterated over, and checked to see if all the values
are positive

The output array is allocated as np.double or np.cdouble based on this
result

The input array is iterated over, and log evaluated on each element in
turn
In either case, you’ve converted a 1pass iteration to a 2pass one.
There are statictypingbased explanations for this behavior too, but I’ll
let someone else present one of those.
Eric
On Mon, 25 May 2020 at 14:33, Brian Racey
Why does numpy produce a runtime warning (invalid value encountered in log) when taking the log of a negative number? I noticed that if you coerce the argument to complex by adding 0j to the negative number, the expected result is produced (i.e. ln(1) = pi*i).
I was surprised I couldn't find a discussion on this, as I would have expected others to have come across this before. Packages like Matlab handle negative numbers automatically by doing the complex conversion. _______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
Thanks. That is for performance and memory which of course is valid for
most use cases. Would it really be much different than doing type/size
checking of all the np.array arguments to a function to ensure the
appropriate final np.array sizes are allocated? I'm not trying to question
current practice, just trying to understand as performance will eventually
be important to me.
Would a "complex default" mode ever make it into numpy, to behave more like
Matlab and other packages with respect to complex number handling? Sure it
would make it marginally slower if enabled, but it might open the door to
better compatibility when porting code to Python.
On Mon, May 25, 2020 at 9:49 AM Eric Wieser
One explanation for this behavior is that doing otherwise would be slow.
Consider an array like
arr = np.array([1]*10**6 + [1]) ret = np.log(arr)
Today, what happens is:
 The output array is allocated as np.double  The input array is iterated over, and log evaluated on each element in turn
For what you describe to happen, the behavior would have to be either:
 The output array is allocated as np.double 
The input array is iterated over, and log evaluated on each element in turn 
If any negative element is encountered, allocate a new array as np.cdouble, copy all the data over, then continue. This results in the whole array being promoted.
or:
 The input array is iterated over, and checked to see if all the values are positive 
The output array is allocated as np.double or np.cdouble based on this result 
The input array is iterated over, and log evaluated on each element in turn
In either case, you’ve converted a 1pass iteration to a 2pass one.
There are statictypingbased explanations for this behavior too, but I’ll let someone else present one of those.
Eric
On Mon, 25 May 2020 at 14:33, Brian Racey
wrote: Why does numpy produce a runtime warning (invalid value encountered in log) when taking the log of a negative number? I noticed that if you coerce the argument to complex by adding 0j to the negative number, the expected result is produced (i.e. ln(1) = pi*i).
I was surprised I couldn't find a discussion on this, as I would have expected others to have come across this before. Packages like Matlab handle negative numbers automatically by doing the complex conversion. _______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
Being relatively new to numpy, I'm learning as I go. Your typing suggestion
helped me come to the conclusion that I need to type and coerce my input
arguments as I'm doing complex math. My test arguments were real, and thus
numpy was producing real results. Doing .astype(np.complex128) to my input
values that are generally complex resolved my issue.
On Mon, May 25, 2020 at 10:09 AM Brian Racey
Thanks. That is for performance and memory which of course is valid for most use cases. Would it really be much different than doing type/size checking of all the np.array arguments to a function to ensure the appropriate final np.array sizes are allocated? I'm not trying to question current practice, just trying to understand as performance will eventually be important to me.
Would a "complex default" mode ever make it into numpy, to behave more like Matlab and other packages with respect to complex number handling? Sure it would make it marginally slower if enabled, but it might open the door to better compatibility when porting code to Python.
On Mon, May 25, 2020 at 9:49 AM Eric Wieser
wrote: One explanation for this behavior is that doing otherwise would be slow.
Consider an array like
arr = np.array([1]*10**6 + [1]) ret = np.log(arr)
Today, what happens is:
 The output array is allocated as np.double  The input array is iterated over, and log evaluated on each element in turn
For what you describe to happen, the behavior would have to be either:
 The output array is allocated as np.double 
The input array is iterated over, and log evaluated on each element in turn 
If any negative element is encountered, allocate a new array as np.cdouble, copy all the data over, then continue. This results in the whole array being promoted.
or:
 The input array is iterated over, and checked to see if all the values are positive 
The output array is allocated as np.double or np.cdouble based on this result 
The input array is iterated over, and log evaluated on each element in turn
In either case, you’ve converted a 1pass iteration to a 2pass one.
There are statictypingbased explanations for this behavior too, but I’ll let someone else present one of those.
Eric
On Mon, 25 May 2020 at 14:33, Brian Racey
wrote: Why does numpy produce a runtime warning (invalid value encountered in log) when taking the log of a negative number? I noticed that if you coerce the argument to complex by adding 0j to the negative number, the expected result is produced (i.e. ln(1) = pi*i).
I was surprised I couldn't find a discussion on this, as I would have expected others to have come across this before. Packages like Matlab handle negative numbers automatically by doing the complex conversion. _______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
On Mon, 20200525 at 10:09 0400, Brian Racey wrote:
Thanks. That is for performance and memory which of course is valid for most use cases. Would it really be much different than doing type/size checking of all the np.array arguments to a function to ensure the appropriate final np.array sizes are allocated? I'm not trying to question current practice, just trying to understand as performance will eventually be important to me.
Would a "complex default" mode ever make it into numpy, to behave more like Matlab and other packages with respect to complex number handling? Sure it would make it marginally slower if enabled, but it might open the door to better compatibility when porting code to Python.
From my side main argument in favor of the current behaviour is that you, as someone working with complex numbers, likely immediately knows
I think the SciPy versions may have such a default, or there is such a functionality hidden somewhere (maybe even the switching behaviour). I am not sure anyone actually uses those, so it may not be a good idea to use them to be honest. The type safety aspects are that you do can get float or complex results randomly, which of course is fine for much code... that what you want is to use `np.log(..., dtype=...)` or cast the input to complex. But someone not used to complex numbers may be very surprised if they suddenly have a complex result after a long calculation. That said, there is a problem here, since it is a bit clumsy to force a complex result. `np.log(..., dtype=np.complex128)` works, but hard codes double precision. `np.log(arr + 0j)` works, but may look strange (I will assume that `log` is so slow that the overhead is not very relevant). I am not sure that if the use case is actually big enough to worry about it, i.e. if you work with complex numbers, you may be fine with just converting to complex once early on...  Sebastian
On Mon, May 25, 2020 at 9:49 AM Eric Wieser < wieser.eric+numpy@gmail.com> wrote:
One explanation for this behavior is that doing otherwise would be slow.
Consider an array like
arr = np.array([1]*10**6 + [1]) ret = np.log(arr)
Today, what happens is:
 The output array is allocated as np.double  The input array is iterated over, and log evaluated on each element in turn
For what you describe to happen, the behavior would have to be either:
 The output array is allocated as np.double 
The input array is iterated over, and log evaluated on each element in turn 
If any negative element is encountered, allocate a new array as np.cdouble, copy all the data over, then continue. This results in the whole array being promoted.
or:
 The input array is iterated over, and checked to see if all the values are positive 
The output array is allocated as np.double or np.cdouble based on this result 
The input array is iterated over, and log evaluated on each element in turn
In either case, you’ve converted a 1pass iteration to a 2pass one.
There are statictypingbased explanations for this behavior too, but I’ll let someone else present one of those.
Eric
On Mon, 25 May 2020 at 14:33, Brian Racey
wrote: Why does numpy produce a runtime warning (invalid value encountered in log) when taking the log of a negative number? I noticed that if you coerce the argument to complex by adding 0j to the negative number, the expected result is produced (i.e. ln(1) = pi*i).
I was surprised I couldn't find a discussion on this, as I would have expected others to have come across this before. Packages like Matlab handle negative numbers automatically by doing the complex conversion. _______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
On Mon, May 25, 2020 at 10:36 AM Sebastian Berg
On Mon, 20200525 at 10:09 0400, Brian Racey wrote:
Would a "complex default" mode ever make it into numpy, to behave more like Matlab and other packages with respect to complex number handling? Sure it would make it marginally slower if enabled, but it might open the door to better compatibility when porting code to Python.
I think the SciPy versions may have such a default, or there is such a functionality hidden somewhere (maybe even the switching behaviour). I am not sure anyone actually uses those, so it may not be a good idea to use them to be honest.
The versions in `np.lib.scimath` behave like this. Of course, people do use them when they want to deal with real numbers as subsets of the complex numbers.  Robert Kern
On Mon, 20200525 at 11:10 0400, Robert Kern wrote:
On Mon, May 25, 2020 at 10:36 AM Sebastian Berg < sebastian@sipsolutions.net> wrote:
On Mon, 20200525 at 10:09 0400, Brian Racey wrote:
Would a "complex default" mode ever make it into numpy, to behave more like Matlab and other packages with respect to complex number handling? Sure it would make it marginally slower if enabled, but it might open the door to better compatibility when porting code to Python.
I think the SciPy versions may have such a default, or there is such a functionality hidden somewhere (maybe even the switching behaviour). I am not sure anyone actually uses those, so it may not be a good idea to use them to be honest.
The versions in `np.lib.scimath` behave like this. Of course, people do use them when they want to deal with real numbers as subsets of the complex numbers.
True, I guess I just used complex numbers too rarely in programs (i.e. never central to any programming project). It seems this is actually also exposed as `np.emath`, which is maybe a better entry point? And I guess the scipy namespace uses them.  Sebastian
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
My Googling revealed none of this. I don't have anyone to talk to about
using numpy, so Google (and this group) is all I have. This was extremely
useful: https://numpy.org/devdocs/user/numpyformatlabusers.html so
perhaps it could be extended to point out those modules and entry points if
it isn't documented elsewhere.
On Mon, May 25, 2020 at 11:17 AM Sebastian Berg
On Mon, 20200525 at 11:10 0400, Robert Kern wrote:
On Mon, May 25, 2020 at 10:36 AM Sebastian Berg < sebastian@sipsolutions.net> wrote:
On Mon, 20200525 at 10:09 0400, Brian Racey wrote:
Would a "complex default" mode ever make it into numpy, to behave more like Matlab and other packages with respect to complex number handling? Sure it would make it marginally slower if enabled, but it might open the door to better compatibility when porting code to Python.
I think the SciPy versions may have such a default, or there is such a functionality hidden somewhere (maybe even the switching behaviour). I am not sure anyone actually uses those, so it may not be a good idea to use them to be honest.
The versions in `np.lib.scimath` behave like this. Of course, people do use them when they want to deal with real numbers as subsets of the complex numbers.
True, I guess I just used complex numbers too rarely in programs (i.e. never central to any programming project).
It seems this is actually also exposed as `np.emath`, which is maybe a better entry point? And I guess the scipy namespace uses them.
 Sebastian
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
I wasted a good 2 weeks because of that behavior of Matlab back in the day
and I think that is one of the cardinal sins that matlab commits. If need
be there are alternatives as mentioned before but I definitely do not
prefer this coercion at all.
On Mon, May 25, 2020 at 5:18 PM Sebastian Berg
On Mon, 20200525 at 11:10 0400, Robert Kern wrote:
On Mon, May 25, 2020 at 10:36 AM Sebastian Berg < sebastian@sipsolutions.net> wrote:
On Mon, 20200525 at 10:09 0400, Brian Racey wrote:
Would a "complex default" mode ever make it into numpy, to behave more like Matlab and other packages with respect to complex number handling? Sure it would make it marginally slower if enabled, but it might open the door to better compatibility when porting code to Python.
I think the SciPy versions may have such a default, or there is such a functionality hidden somewhere (maybe even the switching behaviour). I am not sure anyone actually uses those, so it may not be a good idea to use them to be honest.
The versions in `np.lib.scimath` behave like this. Of course, people do use them when they want to deal with real numbers as subsets of the complex numbers.
True, I guess I just used complex numbers too rarely in programs (i.e. never central to any programming project).
It seems this is actually also exposed as `np.emath`, which is maybe a better entry point? And I guess the scipy namespace uses them.
 Sebastian
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
_______________________________________________ NumPyDiscussion mailing list NumPyDiscussion@python.org https://mail.python.org/mailman/listinfo/numpydiscussion
On Mon, May 25, 2020 at 11:17 AM Sebastian Berg
On Mon, 20200525 at 11:10 0400, Robert Kern wrote:
On Mon, May 25, 2020 at 10:36 AM Sebastian Berg < sebastian@sipsolutions.net> wrote:
On Mon, 20200525 at 10:09 0400, Brian Racey wrote:
Would a "complex default" mode ever make it into numpy, to behave more like Matlab and other packages with respect to complex number handling? Sure it would make it marginally slower if enabled, but it might open the door to better compatibility when porting code to Python.
I think the SciPy versions may have such a default, or there is such a functionality hidden somewhere (maybe even the switching behaviour). I am not sure anyone actually uses those, so it may not be a good idea to use them to be honest.
The versions in `np.lib.scimath` behave like this. Of course, people do use them when they want to deal with real numbers as subsets of the complex numbers.
True, I guess I just used complex numbers too rarely in programs (i.e. never central to any programming project).
It seems this is actually also exposed as `np.emath`, which is maybe a better entry point? And I guess the scipy namespace uses them.
Ah, yes, that's the preferred alias, though the documentation page for it seems to be a little buggy (using `np.lib.scimath` instead `np.emath`; telling you to look at the docstrings for the individual functions, but they don't exist in the documentation).  Robert Kern
Would a "complex default" mode ever make it into numpy, to behave more like Matlab and other packages with respect to complex number handling? Sure it would make it marginally slower if enabled, but it might open the door to better compatibility when porting code to Python.
numpy already has the "complex default" log function: numpy.lib.scimath.log . There are other useful gems in that module, for example a "complex default" sqrt function Ciao, Tiziano
participants (6)

Brian Racey

Eric Wieser

Ilhan Polat

Robert Kern

Sebastian Berg

Tiziano Zito