Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: C Module's '1.#INF' changes to 'inf' at Python

5 views
Skip to first unread message

Robert Kern

unread,
Jan 8, 2010, 10:36:44 AM1/8/10
to pytho...@python.org
On 2010-01-08 07:48 AM, CELEN Erman wrote:
> Hi All,
>
> My problem is that I’ve noticed a strange behavior in Python while
> handling FPEs on Windows after switching compilers (msvc8 to msvc9) and
> I am trying to find out how Python handles INF values to figure out
> where the problem might be.
>
> The problem appeared when we noticed that behavior of Numeric (older
> version of NumPy) library has changed when dealing with Floating-Point
> Exceptions. We are building our own slightly modified version of Python
> in-house (including Numeric/NumPy) and when we switched from the msvc8
> to msvc9 compiler, Numeric started to return ‘-inf’ as a result of
> ‘Numeric.log10(0.0)’ instead of rasing an OverflowError. I know that
> Numeric is using umath instead of the math library and since
> math.log10(0.0) is still raising an Error (which is ValueError in 2.6
> and OverflowError in 2.4, but still an error) I thought that it might
> have something to do with how umath or Numeric handles the input or
> return values of log functions.

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

Mark Dickinson

unread,
Jan 9, 2010, 4:22:29 AM1/9/10
to
On Jan 8, 3:36 pm, Robert Kern <robert.k...@gmail.com> wrote:
> On 2010-01-08 07:48 AM, CELEN Erman wrote:
> > My problem is that I’ve noticed a strange behavior in Python while
> > handling FPEs on Windows after switching compilers (msvc8 to msvc9) and
> > I am trying to find out how Python handles INF values to figure out
> > where the problem might be.
> > [...]

>
> 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?

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

CELEN Erman

unread,
Jan 11, 2010, 1:27:07 PM1/11/10
to pytho...@python.org
> 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.

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.

Robert Kern

unread,
Jan 11, 2010, 1:52:53 PM1/11/10
to pytho...@python.org
On 2010-01-11 12:27 PM, CELEN Erman wrote:
>> 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.
>
> 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").

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.

CELEN Erman

unread,
Jan 11, 2010, 3:31:15 PM1/11/10
to pytho...@python.org, Robert Kern
>> (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,

Robert Kern

unread,
Jan 11, 2010, 5:14:04 PM1/11/10
to pytho...@python.org

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

0 new messages