Numeric.log10() will check to see if the errno was set to ERANGE. It does not
check if a floating point exception flag was set, which is tricky to do across
platforms. The newer numpy can do it because we've finally managed to implement
all of that platform-specific code, but the earlier Numeric does not.
Presumably, the msvc8 C runtime's implementation of log10() sets errno and the
msvc9 runtime's version does not.
> Before hunting blindly I wanted to see how Python interprets INF
> results. I built a simple module with only one function that causes an
> FPE with log10(0.0) using C’s math library and prints the results with
> printf. Then I imported that module from python, called the function and
> printed the result in python too to see if there are any differences
> between two values (which I found out that there are)
Python 2.6 changed the string representations of the special floating point
values inf and nan. Previously, the string representation was left up to the C
runtime, so they differed between platforms. Python 2.6 normalized the string
representation across all platforms. The underlying values are the same. What
version of Python are you using?
--
Robert Kern
"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
In addition to this, for good or ill Python 2.6 also standardized
exceptional behaviour for the math module functions: log10(0.0) and
sqrt(-1) used to produce different results across implementations, but
now both should consistently produce ValueError regardless of the
platform. This is achieved by dealing directly with special cases in
the input before delegating to the relevant libm function; this of
course has an associated performance cost. There are some notes on
the (intended) current behaviour at the top of the Modules/
mathmodule.c file:
http://svn.python.org/view/*checkout*/python/branches/release26-maint/Modules/mathmodule.c
--
Mark
It doesn't seem like C part is changed. I confirmed that the behavior of log10(0.0) in C's standard math.h library didn't change between compilers (msvc8 and msvc9 both sets the errno to 34(ERANGE)). Now I'm thinking that this setting errno problem is happening somewhere in Numeric's log10 wrappers.
As I see, Numeric's "PyUFunc_GenericFunction" checks errno value to see if the called function has set it and if it is non-zero, it calls math_error which raises the exception. The problem is that now errno is not being set but I can't see why since I can't step into that redirected function call ("*(double *)op = ((DoubleUnaryFunc *)func)(*(double *)ip1)" where function value is "0x01c4ede0 log10").
I am wondering which functions are actually being called when I call log10(0.0). Could you (or anybody) point me where this errno is supposed to be set in Numeric or umath when I call log10(0.0) so that I can take a look at why this is not being the case.
(I also noticed that this behavior is same under standard NumPy 1.4 with standard Python 2.6 on Windows. If you call numpy.log10(0.0) you will get an "-inf" and no exceptions will be raised. Which is not the case with Python's standard math.log10(0.0) which will raise a ValueError)
Best Regards,
Ali Erman CELEN
Platform Specialists / Porting
This email and any attachments are intended solely for the use of the individual or entity to whom it is addressed and may be confidential and/or privileged. If you are not one of the named recipients or have received this email in error, (i) you should not read, disclose, or copy it, (ii) please notify sender of your receipt by reply email and delete this email and all attachments, (iii) Dassault Systemes does not accept or assume any liability or responsibility for any use of or reliance on this email.For other languages, go to http://www.3ds.com/terms/email-disclaimer.
This is the math library's log10() function.
> I am wondering which functions are actually being called when I call log10(0.0). Could you (or anybody) point me where this errno is supposed to be set in Numeric or umath when I call log10(0.0) so that I can take a look at why this is not being the case.
errno gets set to 0 before PyUFunc_GenericFunction calls the underlying log10()
function. Other than that, Numeric does not set errno.
> (I also noticed that this behavior is same under standard NumPy 1.4 with standard Python 2.6 on Windows. If you call numpy.log10(0.0) you will get an "-inf" and no exceptions will be raised. Which is not the case with Python's standard math.log10(0.0) which will raise a ValueError)
Correct. This is numpy's intended behavior. See numpy.seterr() to enable
exceptions if you want them.
Numpy.seterr() doesn't seem to be working in case of log10(0.0) (output with all standard: Python2.6 with NumPy1.4 on Windows-32bit is below)
Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> numpy.seterr()
{'over': 'ignore', 'divide': 'ignore', 'invalid': 'ignore', 'under': 'ignore'}
>>> numpy.int16(32000) * numpy.int16(3)
30464
>>> numpy.log10(0.0)
-inf
>>> numpy.seterr(all='raise')
{'over': 'ignore', 'divide': 'ignore', 'invalid': 'ignore', 'under': 'ignore'}
>>> numpy.int16(32000) * numpy.int16(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FloatingPointError: overflow encountered in short_scalars
>>> numpy.log10(0.0)
-inf
>>> numpy.log10(-1.0)
nan
>>> numpy.seterr()
{'over': 'raise', 'divide': 'raise', 'invalid': 'raise', 'under': 'raise'}
>>>
Also I'm pretty sure C's log10 (math.h) still sets errno to ERANGE (34) with both msvc8 and msvc9. That's why I thought a Numeric/Numpy wrapper might be involved but you are saying, if I'm not mistaken, math library's log10() function is called directly (without any special log10 wrappers) and only time Numeric changes errno is where it sets errno=0 before calling C's log10. Somehow, errno is not being set or gets changed/masked during this whole log10 call procedure and this might also be the reason why current version of Numpy is missing the error even if we do numpy.seterr(all='raise').
So, why do you think errno is not being set under Python with Numeric.log10 (or numpy.log10() which also seems to have the same 'letting overflow error through' issue) ?
Thanks for your help,
That might be an issue with how numpy is detecting the floating point exception
on Windows. Please report it. It works fine on OS X:
In [1]: np.seterr(all='raise')
Out[1]: {'divide': 'print', 'invalid': 'print', 'over': 'print', 'under': 'ignore'}
In [2]: np.log10(0.0)
---------------------------------------------------------------------------
FloatingPointError Traceback (most recent call last)
/Users/rkern/<ipython console> in <module>()
FloatingPointError: divide by zero encountered in log10
In [3]: np.log10(-1.0)
---------------------------------------------------------------------------
FloatingPointError Traceback (most recent call last)
/Users/rkern/<ipython console> in <module>()
FloatingPointError: invalid value encountered in log10