Re: math.nroot [was Re: A brief question.]

2005-07-15 Thread Michael Hudson
Tim Peters <[EMAIL PROTECTED]> writes:

> [Tim]
> >> Ah, but as I've said before, virtually all C compilers on 754 boxes
> >> support _some_ way to get at this stuff.  This includes gcc before C99
> >> and fenv.h -- if the platforms represented in fpectlmodule.c were
> >> happy to use gcc, they all could have used the older gcc spellings
> >> (which are in fpectlmodule.c, BTW, under the __GLIBC__ #ifdef).
> 
> [Michael] 
> > Um, well, no, not really.  The stuff under __GLIBC___ unsurprisingly
> > applies to platforms using the GNU project's implementation of the C
> > library, and GCC is used on many more platforms than just that
> > (e.g. OS X, FreeBSD).
> 
> Good point taken:  parings of C compilers and C runtime libraries are
> somewhat fluid.
> 
> So if all the platforms represented in fpectlmodule.c were happy to
> use glibc, they all could have used the older glibc spellings. 
> Apparently the people who cared enough on those platforms to
> contribute code to fpectlmodule.c did not want to use glibc, though. 

It may not have been possible for them, after a little googling.  It
seems that while glibc is theoretically portable to systems other than
linux, in practice it ain't.

> In the end, I still don't know why there would be a reason to hope
> that an endless variety of other libms would standardize on the C99
> spellings.

Point.  But as you said in the post I replied to, soon (maybe even
now) there won't be an "endless variety of other libms" to worry
about.

> > ...
> >  Even given that, the glibc section looks mighty Intel specific to me (I 
> > don't
> > see why 0x1372 should have any x-architecture meaning).
> 
> Why not?  I don't know whether glibc ever did this, but Microsoft's
> spelling of this stuff used to, on Alphas (when MS compilers still
> supported Alphas), pick apart the bits and rearrange them into the
> bits needed for the Alpha's FPU control registers.  

Well, I considered that but decided that it was far too insane.  Maybe
that was insufficient cynicism :)

In any case, glibc's docs today only mention the C99 (and C99-like,
for setting traps) interfaces, and I can't be arsed to go through old
docs to see if _FPU_SETCW or __setfpucw were ever documented and if so
what they were documented to do.

> > One thing GCC doesn't yet support, it turns out, is the "#pragma STDC
> > FENV_ACCESS ON" gumpf, which means the optimiser is all too willing to
> > reorder
> > 
> >feclearexcept(FE_ALL_EXCEPT);
> >r = x * y;
> >fe = fetestexcept(FE_ALL_EXCEPT);
> >
> > into
> > 
> >feclearexcept(FE_ALL_EXCEPT);
> >fe = fetestexcept(FE_ALL_EXCEPT);
> >r = x * y;
> > 
> > Argh!  Declaring r 'volatile' made it work.
>  
> Oh, sigh.  One of the lovely ironies in all this is that CPython
> _could_ make for an excellent 754 environment, precisely because it
> does such WYSIWYG code generation. 

One of my motivations here (other than the instantly discountably one
of aesthetic purity :) is to make Python a good system for prototyping
numeric codes.

> Optimizing-compiler writers hate hidden side effects, and every fp
> operation in 754 is swimming in them -- but Python couldn't care
> much less.

Thing is, I don't see how this particular stuff should be that hard to
implement -- if you have an optimizing compiler that can move code
around, presumably you have some way of saying what can't be moved
past what else.  But you're not going to catch me diving into GCC's
sources :) (In other news, passing -frounding-math to GCC may also
have the desired effect, but I haven't tested this).

> Anyway, you're rediscovering the primary reason you have to pass a
> double lvalue to the PyFPE_END_PROTECT protect macro. 
> PyFPE_END_PROTECT(v) expands to an expression including the
> subexpression
> 
> PyFPE_dummy(&(v))
> 
> where PyFPE_dummy() is an extern that ignores its double* argument. 
> The point is that this dance prevents C optimizers from moving the
> code that computes v below the code generated for
> PyFPE_END_PROTECT(v).  Since v is usually used soon after in the
> routine, it also discourages the optimizer from moving code up above
> the PyFPE_END_PROTECT(v) (unless the C does cross-file analysis, it
> has to assume that PyFPE_dummy(&(v)) may change the value of v). 
> These tricks may be useful here too -- fighting C compilers to the
> death is part of this game, alas.

I did read those comments.  Maybe passing the address of the result
variable to the routine that checks the flags and decides whether to
raise an exception would be a good hack (and, yes, writing that
function in another file so GCC doesn't bloody well inline it and then
rearrange all my code).

> PyFPE_END_PROTECT() incorporates an even stranger trick, and I wonder
> how gcc deals with it.  The Pentium architecture made an agonizing
> (for users who care) choice:  if you have a particular FP trap enabled
> (let's say overflow), and you do an fp operation that overflows, the
> trap doesn't actually fire unt

Re: math.nroot [was Re: A brief question.]

2005-07-14 Thread Tim Peters
[Michael Hudson]
> In what way does C99's fenv.h fail?  Is it just insufficiently
> available, or is there some conceptual lack?

[Tim Peters]
 Just that it's not universally supported.  Look at fpectlmodule.c for
 a sample of the wildly different ways it _is_ spelled across some
 platforms.

[Michael]
>>> C'mon, fpectlmodule.c is _old_.  Maybe I'm stupidly optimistic, but
>>> perhaps in the last near-decade things have got a little better here.

[Tim]
>> Ah, but as I've said before, virtually all C compilers on 754 boxes
>> support _some_ way to get at this stuff.  This includes gcc before C99
>> and fenv.h -- if the platforms represented in fpectlmodule.c were
>> happy to use gcc, they all could have used the older gcc spellings
>> (which are in fpectlmodule.c, BTW, under the __GLIBC__ #ifdef).

[Michael] 
> Um, well, no, not really.  The stuff under __GLIBC___ unsurprisingly
> applies to platforms using the GNU project's implementation of the C
> library, and GCC is used on many more platforms than just that
> (e.g. OS X, FreeBSD).

Good point taken:  parings of C compilers and C runtime libraries are
somewhat fluid.

So if all the platforms represented in fpectlmodule.c were happy to
use glibc, they all could have used the older glibc spellings. 
Apparently the people who cared enough on those platforms to
contribute code to fpectlmodule.c did not want to use glibc, though. 
In the end, I still don't know why there would be a reason to hope
that an endless variety of other libms would standardize on the C99
spellings.  For backward compatibility, they have to continue
supporting their old spellings too, and then what's in it for them to
supply aliases?  Say I'm SGI, struggling as often as not just to stay
in business.  I'm unlikely to spend what little cash I have to make it
easier for customers to jump ship .

> ...
>  Even given that, the glibc section looks mighty Intel specific to me (I don't
> see why 0x1372 should have any x-architecture meaning).

Why not?  I don't know whether glibc ever did this, but Microsoft's
spelling of this stuff used to, on Alphas (when MS compilers still
supported Alphas), pick apart the bits and rearrange them into the
bits needed for the Alpha's FPU control registers.  Saying that bit
0x10 (whatever) is "the overflow flag" (whatever) is as much a
x-platform API as saying that the expansion of the macro FE_OVERFLOW
is "the overflow flag".  Fancy pants symbolic names are favored by
"computer science" types these days, but real numeric programmers have
always been delighted to wallow in raw bits .

...

> One thing GCC doesn't yet support, it turns out, is the "#pragma STDC
> FENV_ACCESS ON" gumpf, which means the optimiser is all too willing to
> reorder
> 
>feclearexcept(FE_ALL_EXCEPT);
>r = x * y;
>fe = fetestexcept(FE_ALL_EXCEPT);
>
> into
> 
>feclearexcept(FE_ALL_EXCEPT);
>fe = fetestexcept(FE_ALL_EXCEPT);
>r = x * y;
> 
> Argh!  Declaring r 'volatile' made it work.
 
Oh, sigh.  One of the lovely ironies in all this is that CPython
_could_ make for an excellent 754 environment, precisely because it
does such WYSIWYG code generation.  Optimizing-compiler writers hate
hidden side effects, and every fp operation in 754 is swimming in them
-- but Python couldn't care much less.

Anyway, you're rediscovering the primary reason you have to pass a
double lvalue to the PyFPE_END_PROTECT protect macro. 
PyFPE_END_PROTECT(v) expands to an expression including the
subexpression

PyFPE_dummy(&(v))

where PyFPE_dummy() is an extern that ignores its double* argument. 
The point is that this dance prevents C optimizers from moving the
code that computes v below the code generated for
PyFPE_END_PROTECT(v).  Since v is usually used soon after in the
routine, it also discourages the optimizer from moving code up above
the PyFPE_END_PROTECT(v) (unless the C does cross-file analysis, it
has to assume that PyFPE_dummy(&(v)) may change the value of v). 
These tricks may be useful here too -- fighting C compilers to the
death is part of this game, alas.

PyFPE_END_PROTECT() incorporates an even stranger trick, and I wonder
how gcc deals with it.  The Pentium architecture made an agonizing
(for users who care) choice:  if you have a particular FP trap enabled
(let's say overflow), and you do an fp operation that overflows, the
trap doesn't actually fire until the _next_ fp operation (of any kind)
occurs.  You can honest-to-God have, e.g., an overflowing fp add on an
Intel box, and not learn about it until a billion cycles after it
happened (if you don't do more FP operations over the next billion
cycles).

So "the other thing" PyFPE_END_PROTECT does is force a seemingly
pointless double->int conversion (it always coerces 1.0 to an int),
just to make sure that a Pentium will act on any enabled trap that
occurred before it.

If you have in mind just testing flags (and staying away from enabling
HW traps -- and this is the course I recommend), t

Re: math.nroot [was Re: A brief question.]

2005-07-13 Thread Tim Peters
[Steven D'Aprano]
> (All previous quoting ruthlessly snipped.)

And ruthlessly appreciated ;-)

> A question for Tim Peters, as I guess he'll have the most experience in
> this sort of thing.
>
> With all the cross-platform hassles due to the various C compilers not
> implementing the IEEE standard completely or correctly, I wonder how much
> work would be involved for some kind soul to implement their own maths
> library to do the lot, allowing Python to bypass the C libraries
> altogether.
>
> Are you falling over laughing Tim, or thinking what a great idea?

Neither, really.  Doing basic + - * / in SW is way too slow to sell to
programmers who take floats seriously in their work.  For libm, K-C Ng
at Sun was writing fdlibm at the same time Peter Tang & I were writing
a "spirit of 754" libm for Kendall Square Research (early 90's).  KSR
is long gone, and the code was proprietary anyway; fdlibm lives on,
with an MIT-like ("do whatever you want") license, although it doesn't
appear to have enjoyed maintenance work for years now:

http://www.netlib.org/fdlibm/

fdlibm is excellent (albeit largely inscrutable to non-specialists) work.

I believe that, at some point, glibc replaced its math functions with
fdlibm's, and went on to improve them.  Taking advantage of those
improvements may (or may not) raise licensing issues Python can't live
with.

There are at least two other potential issues with using it:

1. Speed again.  The libm I wrote for KSR was as accurate and relentlessly
   754-conforming as fdlibm, but approximately 10x faster.  There's
   an enormous amount of optimization you can do if you can exploit every
   quirk of the HW you're working on -- and the code I wrote was entirely
   unportable, non-standard C, which couldn't possibly run on any HW other
   than KSR's custom FPU.  C compiler vendors at least used to spend a lot
   of money similarly crafting libraries that exploited quirks of the HW they
   were targeting, and lots of platforms still have relatively fast libms as a
   result.  fdlibm aims to run on "almost any" 32-bit 754 box, and pays for
   that in comparative runtime sloth.  .  Since fdlibm was written at Sun over
   a decade ago, you can guess that it wasn't primarily aiming at the Pentium
   architecture.

2. Compatibility with the platform libm.  Some users will be unhappy unless
   the stuff they get from Python is quirk-for-quirk and bug-for-bug identical
   to the stuff they get from other languages on their platform.  There's really
   no way to do that unless Python uses the same libm.  For example,
   many people have no real idea what they're doing with libm functions, and
   value reproducibility over anything else -- "different outcomes means
   one of them must be in error" is the deepest analysis they can, or maybe
   just have time, to make.  Alas, for many uses of libm, that's a defensible
   (albeit appalling <0.6 wink>) attitude (e.g., someone slings sin() and cos()
   to plot a circle in a GUI -- when snapping pixels to the closest grid point,
   the tiniest possible rounding difference can make a pixel "jump" to a
   neighboring pixel, and then "it's a bug" if Python doesn't reproduce the
   same pixel plotting accidents as, e.g., the platform C or JavaScript).

> What sort of work is needed? Is it, say, as big a job as maintaining
> Python? Bigger? One weekend spent working solidly?

Half a full-time year if done from scratch by a numeric programming
expert.  Maybe a few weeks if building on fdlibm, which probably needs
patches to deal with modern compilers (e.g.,

http://www.netlib.org/fdlibm/readme

has no date on it, but lists as "NOT FIXED YET":

3. Compiler failure on non-standard code
Statements like
*(1+(int*)&t1) = 0;
are not standard C and cause some optimizing compilers (e.g.
GCC) to generate bad code under optimization.These cases
are to be addressed in the next release.
).
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-13 Thread Michael Hudson
Tim Peters <[EMAIL PROTECTED]> writes:

> [Michael Hudson]
> > I doubt anyone else is reading this by now, so I've trimmed quotes
> > fairly ruthlessly :)
> 
> Damn -- there goes my best hope at learning how large a message gmail
> can handle before blowing up .  OK, I'll cut even more.

Heh.

> [Michael]
> >>> Can't we use the stuff defined in Appendix F and header  of
> >>> C99 to help here?  I know this stuff is somewhat optional, but it's
> >>> available AFAICT on the platforms I actually use (doesn't mean it
> >>> works, of course).
> 
> [Tim]
> >> It's entirely optional part of C99.
> 
> > Hmm, is  optional?  I'm not finding those words.  I know
> > Appendix F is.
> 
> fenv.h is required, but the standard is carefully worded so that
> fenv.h may not be of any actual use.  For example, a conforming
> implementation can define FE_ALL_EXCEPT as 0 (meaning it doesn't
> define _any_ of the (optional!) signal-name macros:  FE_DIVBYZERO,
> etc).  That in turn makes feclearexcept() (& so on) pretty much
> useless -- you couldn't specify any flags.

Makes sense.

> >> The most important example of a compiler that doesn't support any of
> >> that stuff is Microsoft's, although they have their own MS-specific
> >> ways to spell most of it.
> 
> > OK, *that's* a serious issue.
> > 
> > If you had to guess, do you think it likely that MS would ship fenv.h
> > in the next interation of VC++?
> 
> Sadly not.  If they wanted to do that, they had plenty of time to do
> so before VC 7.1 was released (C99 ain't exactly new anymore).  As it
> says on
> 
> http://en.wikipedia.org/wiki/C_programming_language
> 
> MS and Borland (among others) appear to have no interest in C99.
> 
> In part I expect this is because C doesn't pay their bills nearly so
> much as C++ does, and C99 isn't a standard from the C++ world.

This also makes sense, in a slightly depressing way.

> >>> In what way does C99's fenv.h fail?  Is it just insufficiently
> >>> available, or is there some conceptual lack?
> 
> >> Just that it's not universally supported.  Look at fpectlmodule.c for
> >> a sample of the wildly different ways it _is_ spelled across some
> >> platforms.
> 
> > C'mon, fpectlmodule.c is _old_.  Maybe I'm stupidly optimistic, but
> > perhaps in the last near-decade things have got a little better here.
> 
> Ah, but as I've said before, virtually all C compilers on 754 boxes
> support _some_ way to get at this stuff.  This includes gcc before C99
> and fenv.h -- if the platforms represented in fpectlmodule.c were
> happy to use gcc, they all could have used the older gcc spellings
> (which are in fpectlmodule.c, BTW, under the __GLIBC__ #ifdef).

Um, well, no, not really.  The stuff under __GLIBC___ unsurprisingly
applies to platforms using the GNU project's implementation of the C
library, and GCC is used on many more platforms than just that
(e.g. OS X, FreeBSD).  This is all part of the "what exactly are you
claiming supports 754, again?" game, I guess.  Even given that, the
glibc section looks mighty Intel specific to me (I don't see why
0x1372 should have any x-architecture meaning).

Now that GCC supports, or aims to support, or will one day support C99
I think you're right in that any GCC-using code can use the same
spelling.

One thing GCC doesn't yet support, it turns out, is the "#pragma STDC
FENV_ACCESS ON" gumpf, which means the optimiser is all too willing to
reorder

feclearexcept(FE_ALL_EXCEPT);
r = x * y;
fe = fetestexcept(FE_ALL_EXCEPT);

into 

feclearexcept(FE_ALL_EXCEPT);
fe = fetestexcept(FE_ALL_EXCEPT);
r = x * y;

Argh!  Declaring r 'volatile' made it work.

> But they didn't, so they're using "minority" compilers.  I used to
> write compilers for a living, but I don't think this is an inside
> secret anymore : there are a lot fewer C compiler writers than
> there used to be, and a lot fewer companies spending a lot less
> money on developing C compilers than there used to be.

Indeed.  Also, less architectures and less C libraries.

> As with other parts of C99, I'd be in favor of following its lead, and
> defining Py_ versions of the relevant macros and functions.

Makes sense!

> >> A maze of #ifdefs could work too, provided we defined a
> >> PyWhatever_XYZ API to hide platform spelling details.
> 
> > Hopefully it wouldn't be that bad a maze; frankly GCC & MSVC++ covers
> > more than all the cases I care about.
> 
> I'd be happy to settle for just those two at the start,  As with
> threading too, Python has suffered from trying to support dozens of
> unreasonable platforms, confined to the tiny subset of abilities
> common to all of them.  If, e.g., HP-UX wants a good Python thread or
> fp story, let HP contribute some work for a change.  I think we have
> enough volunteers to work out good gcc and MSVC stories -- although I
> expect libm to be an everlasting headache

Well, yes.  I think a 'thin wrapper' approach like some of the os
module stuff makes sense here.

Cheers,
mwh


Re: math.nroot [was Re: A brief question.]

2005-07-12 Thread Steven D'Aprano
(All previous quoting ruthlessly snipped.)

A question for Tim Peters, as I guess he'll have the most experience in
this sort of thing.

With all the cross-platform hassles due to the various C compilers not
implementing the IEEE standard completely or correctly, I wonder how much
work would be involved for some kind soul to implement their own maths
library to do the lot, allowing Python to bypass the C libraries
altogether. 

Are you falling over laughing Tim, or thinking what a great idea?

What sort of work is needed? Is it, say, as big a job as maintaining
Python? Bigger? One weekend spent working solidly?



-- 
Steven.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-12 Thread Tim Peters
[Michael Hudson]
> I doubt anyone else is reading this by now, so I've trimmed quotes
> fairly ruthlessly :)

Damn -- there goes my best hope at learning how large a message gmail
can handle before blowing up .  OK, I'll cut even more.

[Michael]
>>> Can't we use the stuff defined in Appendix F and header  of
>>> C99 to help here?  I know this stuff is somewhat optional, but it's
>>> available AFAICT on the platforms I actually use (doesn't mean it
>>> works, of course).

[Tim]
>> It's entirely optional part of C99.

> Hmm, is  optional?  I'm not finding those words.  I know
> Appendix F is.

fenv.h is required, but the standard is carefully worded so that
fenv.h may not be of any actual use.  For example, a conforming
implementation can define FE_ALL_EXCEPT as 0 (meaning it doesn't
define _any_ of the (optional!) signal-name macros:  FE_DIVBYZERO,
etc).  That in turn makes feclearexcept() (& so on) pretty much
useless -- you couldn't specify any flags.

If the implementation chooses to implement the optional Appendix F,
then there are stronger requirements on what fenv.h must define.

>> Python doesn't require C99.

> Sure.  But it would be possible to, say, detect C99 floating point
> facilities at ./configure time and use them if available.

Yes.

>> The most important example of a compiler that doesn't support any of
>> that stuff is Microsoft's, although they have their own MS-specific
>> ways to spell most of it.

> OK, *that's* a serious issue.
> 
> If you had to guess, do you think it likely that MS would ship fenv.h
> in the next interation of VC++?

Sadly not.  If they wanted to do that, they had plenty of time to do
so before VC 7.1 was released (C99 ain't exactly new anymore).  As it
says on

http://en.wikipedia.org/wiki/C_programming_language

MS and Borland (among others) appear to have no interest in C99.

In part I expect this is because C doesn't pay their bills nearly so
much as C++ does, and C99 isn't a standard from the C++ world.

>>> In what way does C99's fenv.h fail?  Is it just insufficiently
>>> available, or is there some conceptual lack?

>> Just that it's not universally supported.  Look at fpectlmodule.c for
>> a sample of the wildly different ways it _is_ spelled across some
>> platforms.

> C'mon, fpectlmodule.c is _old_.  Maybe I'm stupidly optimistic, but
> perhaps in the last near-decade things have got a little better here.

Ah, but as I've said before, virtually all C compilers on 754 boxes
support _some_ way to get at this stuff.  This includes gcc before C99
and fenv.h -- if the platforms represented in fpectlmodule.c were
happy to use gcc, they all could have used the older gcc spellings
(which are in fpectlmodule.c, BTW, under the __GLIBC__ #ifdef).  But
they didn't, so they're using "minority" compilers.  I used to write
compilers for a living, but I don't think this is an inside secret
anymore :  there are a lot fewer C compiler writers than there
used to be, and a lot fewer companies spending a lot less money on
developing C compilers than there used to be.

As with other parts of C99, I'd be in favor of following its lead, and
defining Py_ versions of the relevant macros and functions.  People on
non-C99 platforms who care enough can ugly-up pyport.h with whatever
their platform needs to implement the same functionality, and C99
platforms could make them simple lexical substitutions.  For example,
that's the path we took for Python's C99-workalike Py_uintptr_t and
Py_intptr_t types (although those are much easier to "fake" across
non-C99 platforms).

>> A maze of #ifdefs could work too, provided we defined a
>> PyWhatever_XYZ API to hide platform spelling details.

> Hopefully it wouldn't be that bad a maze; frankly GCC & MSVC++ covers
> more than all the cases I care about.

I'd be happy to settle for just those two at the start,  As with
threading too, Python has suffered from trying to support dozens of
unreasonable platforms, confined to the tiny subset of abilities
common to all of them.  If, e.g., HP-UX wants a good Python thread or
fp story, let HP contribute some work for a change.  I think we have
enough volunteers to work out good gcc and MSVC stories -- although I
expect libm to be an everlasting headache (+ - * are done in HW and
most boxes have fully-conforming 754 semantics for them now; but there
are no pressures like that working toward uniform libm behaviors;
division is still sometimes done in software, but the divide-by-0 is
check is already done by Python and is dead easy to do).
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-12 Thread Michael Hudson
I doubt anyone else is reading this by now, so I've trimmed quotes
fairly ruthlessly :)

Tim Peters <[EMAIL PROTECTED]> writes:

> > Actually, I think I'm confused about when Underflow is signalled -- is it
> > when a denormalized result is about to be returned or when a genuine
> > zero is about to be returned?
> 
> Underflow in 754 is involved -- indeed, the definition is different
> depending on whether the underflow trap is or is not enabled(!). 

!

> > Sure, but we already have a conforming implementation of 854 with
> > settable traps and flags and rounding modes and all that jazz.
> 
> No, we don't, but I assume you're talking about the decimal module. 

Uh, yes.  Apologies for the lack of precision.

> If so, the decimal module enables traps on overflow, invalid
> operation, and divide-by-0 by default.  A conforming implementation
> would have to disable them by default.
> 
> Apart from that difference in defaults, the decimal module does intend
> to conform fully to the proposed decimal FP standard.

Right, that's what I meant.

> > Maybe we should just implement floats in Python.
> 
> Certainly the easiest way to get 754 semantics across boxes!  Been
> there, done that, BTW -- it's mondo slow.

No doubt.

> >>> (In the mean time can we just kill fpectl, please?)
> 
> >> Has it been marked as deprecated yet (entered into the PEP for
> >> deprecated modules, raises deprecation warnings, etc)?  I don't know.
> >> IMO it should become deprecated, but I don't have time to push that.
> 
> > A bit of googling suggests that more people pass --with-fpectl to
> > configure than I expected, but I doubt more than 1% of those actually
> > use the features thus provided (of course, this is a guess).
> 
> I expect 1% is way high.  Before we stopped building fpectl by
> default, Guido asked and heard back that there were no known users
> even at LLNL anymore (the organization that contributed the code).

Interesting.

>  You're seeing native HW fp behavior then.
> 
> >>> But anyway, shouldn't we try to raise exceptions in these cases?
> 
> Note that the only cases you could have been talking about here were
> the plain * and / examples above.

Ah, OK, this distinction passed me by.

> >> Why doesn't Python already supply a fully 754-conforming arithmetic
> >> on 754 boxes?  It's got almost everything to do with implementation
> >> headaches, and very little to do with what users care about.
> >> Because all the C facilities are a x-platform mess, the difference
> >> between calling and not calling libm can be the difference between
> >> using the platform libm or Python needing to write its own libm.
> >> For example, there's no guarantee that math.sqrt(-1) will raise
> >> ValueError in Python, because Python currently relies on the
> >> platform libm sqrt to detect _and report_ errors.  The C standards
> >> don't require much of anything there.
> 
> > Can't we use the stuff defined in Appendix F and header  of
> > C99 to help here?  I know this stuff is somewhat optional, but it's
> > available AFAICT on the platforms I actually use (doesn't mean it
> > works, of course).
> 
> It's entirely optional part of C99.  

Hmm, is  optional?  I'm not finding those words.  I know
Appendix F is.

> Python doesn't require C99.

Sure.  But it would be possible to, say, detect C99 floating point
facilities at ./configure time and use them if available.

> The most important example of a compiler that doesn't support any of
> that stuff is Microsoft's, although they have their own MS-specific
> ways to spell most of it.

OK, *that's* a serious issue.

If you had to guess, do you think it likely that MS would ship fenv.h
in the next interation of VC++?

> > I'm thinking something like this:
> >
> > fexcept_t flags;
> >
> > feclearexcept(FE_ALL_EXCEPT);
> >
> > /* stuff, e.g. r = exp(PyFloat_AS_DOUBLE(x)) */
> >
> > fegetexceptflag(&flags, FE_ALL_EXCEPT)
> > 
> > /* inspect flags to see if any of the flags we're currently trapping
> >   are set */
> 
> Assuming the platform libm sets 754 flags appropriately, that's a fine
> way to proceed on platforms that also support that specific spelling.

It even seems to work, on darwin/ppc (so, with GCC) at least.

> ...
> 
> >>> Well, you can at least be pretty sure that an infinite result is the
> >>> result of an overflow condition, I guess.
> 
> > > There are at least two other causes:  some cases of divide-by-0 (like
> > > 1/0 returns +Inf), and non-exceptional production of an infinite
> > > result from infinite operands (like sqrt(+Inf) should return +Inf, and
> > > there's nothing exceptional about that).
> 
> > Yeah, but I think those can be dealt with (if we really wanted to).
> 
> They certainly could be.

The more I think about it, the less wise I think detecting stuff this
was is sane.

> >> BTW, since there's so little the HW can help us with here in reality
> >> (since there's no portable way to get at it),
> 
> > In what way does C99's fenv.h fail?  Is it just insuf

Re: math.nroot [was Re: A brief question.]

2005-07-11 Thread Tim Peters
[Tim Peters]
>> All Python behavior in the presence of infinities, NaNs, and signed
>> zeroes is a platform-dependent accident, mostly inherited from that
>> all C89 behavior in the presence of infinities, NaNs, and signed
>> zeroes is a platform-dependent crapshoot.

[Michael Hudson]
> As you may have noticed by now, I'd kind of like to stop you saying
> this :) -- at least on platforms where doubles are good old-fashioned
> 754 8-byte values.

[Tim]
 Nope, I hadn't noticed!  I'll stop saying it when it stops being true,
 though .  Note that since there's not even an alpha out for 2.5
 yet, none of the good stuff you did in CVS counts for users yet.

[Michael]
>>> Well, obviously.  OTOH, there's nothing I CAN do that will be useful
>>> for users until 2.5 actually comes out.

[Tim]
>> Sure.  I was explaining why I keep saying what you say you don't want
>> me to say:  until 2.5 actually comes out, what purpose would it serve
>> to stop warning people that 754 special-value behavior is a x-platform
>> crapshoot?  Much of it (albeit less so) will remain a crapshoot after
>> 2.5 comes out too.

[Michael] 
> Well, OK, I phrased my first post badly.  Let me try again:
>
> I want to make this situation better, as you may have noticed.

Yup, I did notice that!  I've even pointed it out.  In a positive light .

> But first, I'm going to whinge a bit, and lay out some stuff that Tim
> at least already knows (and maybe get some stuff wrong, we'll see).
>
> Floating point standards lay out a number of "conditions": Overflow
> (number too large in magnitude to represent), Underflow (non-zero
> number to small in magnitude to represent), Subnormal (non-zero
> number to small in magnitude to represent in a normalized way), ...

 The 754 standard has five of them:  underflow, overflow, invalid
 operation, inexact, and "divide by 0" (which should be understood more
 generally as a singularity; e.g., divide-by-0 is also appropriate for
 log(0)).

>>> OK, the decimal standard has more, which confused me for a bit
>>> (presumably it has more because it doesn't normalize after each
>>> operation).

>> The "conditions" in IBM's decimal standard map, many-to-one, on to a
>> smaller collection of "signals" in that standard.  It has 8 signals:
>> the 5 I named above from 754, plus "clamped", "rounded", and
>> "subnormal".  Distinctions are excruciatingly subtle; e.g., "rounded"
>> and "inexact" would be the same thing in 754, but, as you suggest, in
>> the decimal standard a result can be exact yet also rounded (if it
>> "rounds away" one or more trailing zeroes), due to the unnormalized
>> model.
 
> Right, yes, that last one confused me for a while.
> 
> Why doesn't 754 have subnormal?

Who cares <0.1 wink>.

>  Actually, I think I'm confused about when Underflow is signalled -- is it
> when a denormalized result is about to be returned or when a genuine
> zero is about to be returned?

Underflow in 754 is involved -- indeed, the definition is different
depending on whether the underflow trap is or is not enabled(!).  On
top of that, it's not entirely defined -- some parts are left to the
implementer's discrection.  See

 http://www2.hursley.ibm.com/decimal/854M8208.pdf

for what, from a brief glance, looks very much like the underflow text
in the final 754 standard.

Note that subnormals and underflow are much less a real concern with
754 doubles than with 754 floats, because the latter have such a small
dynamic range.

> For each condition, it should (at some level) is possible to trap each
> condition, or continue in some standard-mandated way (e.g. return 0
> for Underflow).

 754 requires that, yes.

> While ignoring the issue of allowing the user to control this, I do
> wish sometimes that Python would make up it's mind about what it
> does for each condition.

 Guido and I agreed long ago that Python "should", by default, raise an
 exception on overflow, invalid operation, and divide by 0, and "should
 not", by default, raise an exception on underflow or inexact.

>> And, I'll add, "should not" on rounded, clamped and subnormal too.

> Sure, but we already have a conforming implementation of 854 with
> settable traps and flags and rounding modes and all that jazz.

No, we don't, but I assume you're talking about the decimal module. 
If so, the decimal module enables traps on overflow, invalid
operation, and divide-by-0 by default.  A conforming implementation
would have to disable them by default.

Apart from that difference in defaults, the decimal module does intend
to conform fully to the proposed decimal FP standard.

> Maybe we should just implement floats in Python.

Certainly the easiest way to get 754 semantics across boxes!  Been
there, done that, BTW -- it's mondo slow.

 Such defaults favor non-expert use.  Experts may or may not be happy
 with them, so Python "should" also a

Re: math.nroot [was Re: A brief question.]

2005-07-11 Thread Michael Hudson
Tim Peters <[EMAIL PROTECTED]> writes:

> [Tim Peters]
>  All Python behavior in the presence of infinities, NaNs, and signed
>  zeroes is a platform-dependent accident, mostly inherited from that
>  all C89 behavior in the presence of infinities, NaNs, and signed
>  zeroes is a platform-dependent crapshoot.
> 
> [Michael Hudson]
> >>> As you may have noticed by now, I'd kind of like to stop you saying
> >>> this :) -- at least on platforms where doubles are good old-fashioned
> >>> 754 8-byte values.
> 
> [Tim]
> >> Nope, I hadn't noticed!  I'll stop saying it when it stops being true,
> >> though .  Note that since there's not even an alpha out for 2.5
> >> yet, none of the good stuff you did in CVS counts for users yet.
> 
> [Michael] 
> > Well, obviously.  OTOH, there's nothing I CAN do that will be useful
> > for users until 2.5 actually comes out.
> 
> Sure.  I was explaining why I keep saying what you say you don't want
> me to say:  until 2.5 actually comes out, what purpose would it serve
> to stop warning people that 754 special-value behavior is a x-platform
> crapshoot?  Much of it (albeit less so) will remain a crapshoot after
> 2.5 comes out too.

Well, OK, I phrased my first post badly.  Let me try again:

I want to make this situation better, as you may have noticed.

> >>> But first, I'm going to whinge a bit, and lay out some stuff that Tim
> >>> at least already knows (and maybe get some stuff wrong, we'll see).
> >>>
> >>> Floating point standards lay out a number of "conditions": Overflow
> >>> (number too large in magnitude to represent), Underflow (non-zero
> >>> number to small in magnitude to represent), Subnormal (non-zero number
> >>> to small in magnitude to represent in a normalized way), ...
> 
> >> The 754 standard has five of them:  underflow, overflow, invalid
> >> operation, inexact, and "divide by 0" (which should be understood more
> >> generally as a singularity; e.g., divide-by-0 is also appropriate for
> >> log(0)).
> 
> > OK, the decimal standard has more, which confused me for a bit
> > (presumably it has more because it doesn't normalize after each
> > operation).
> 
> The "conditions" in IBM's decimal standard map, many-to-one, on to a
> smaller collection of "signals" in that standard.  It has 8 signals: 
> the 5 I named above from 754, plus "clamped", "rounded", and
> "subnormal".  Distinctions are excruciatingly subtle; e.g., "rounded"
> and "inexact" would be the same thing in 754, but, as you suggest, in
> the decimal standard a result can be exact yet also rounded (if it
> "rounds away" one or more trailing zeroes), due to the unnormalized
> model.

Right, yes, that last one confused me for a while.

Why doesn't 754 have subnormal?  Actually, I think I'm confused about
when Underflow is signalled -- is it when a denormalized result is
about to be returned or when a genuine zero is about to be returned?

> >>> For each condition, it should (at some level) is possible to trap each
> >>> condition, or continue in some standard-mandated way (e.g. return 0
> >>> for Underflow).
> 
> >> 754 requires that, yes.
> 
> >>> While ignoring the issue of allowing the user to control this, I do
> >>> wish sometimes that Python would make up it's mind about what it does
> >>> for each condition.
> 
> >> Guido and I agreed long ago that Python "should", by default, raise an
> >> exception on overflow, invalid operation, and divide by 0, and "should
> >> not", by default, raise an exception on underflow or inexact.
> 
> And, I'll add, "should not" on rounded, clamped and subnormal too.

Sure, but we already have a conforming implementation of 854 with
settable traps and flags and rounding modes and all that jazz.

Maybe we should just implement floats in Python.

> >> Such defaults favor non-expert use.  Experts may or may not be happy
> >> with them, so Python "should" also allow changing the set.
>  
> > Later :)
> 
> That's a problem, though.  754 subsets are barely an improvement over
> what Python does today:

Well, my contention is that the consistent application of one
particular 754 subset would be an improvement.  Maybe I'm wrong!

> > (In the mean time can we just kill fpectl, please?)
> 
> Has it been marked as deprecated yet (entered into the PEP for
> deprecated modules, raises deprecation warnings, etc)?  I don't know. 
> IMO it should become deprecated, but I don't have time to push that.

A bit of googling suggests that more people pass --with-fpectl to
configure than I expected, but I doubt more than 1% of those actually
use the features thus provided (of course, this is a guess).

> >>> There are a bunch of conditions which we shouldn't and don't trap by
> >>> default -- Underflow for example.  For the conditions that probably should
> >>> result in an exception, there are inconsistencies galore:
> >>>
> >>> >>> inf = 1e300 * 1e300 # <- Overflow, no exception
> >>> >>> nan = inf/inf # <- InvalidOperation, no exception
> 
> >> Meaning you're r

Re: math.nroot [was Re: A brief question.]

2005-07-07 Thread Tim Peters
[Tim Peters]
 All Python behavior in the presence of infinities, NaNs, and signed
 zeroes is a platform-dependent accident, mostly inherited from that
 all C89 behavior in the presence of infinities, NaNs, and signed
 zeroes is a platform-dependent crapshoot.

[Michael Hudson]
>>> As you may have noticed by now, I'd kind of like to stop you saying
>>> this :) -- at least on platforms where doubles are good old-fashioned
>>> 754 8-byte values.

[Tim]
>> Nope, I hadn't noticed!  I'll stop saying it when it stops being true,
>> though .  Note that since there's not even an alpha out for 2.5
>> yet, none of the good stuff you did in CVS counts for users yet.

[Michael] 
> Well, obviously.  OTOH, there's nothing I CAN do that will be useful
> for users until 2.5 actually comes out.

Sure.  I was explaining why I keep saying what you say you don't want
me to say:  until 2.5 actually comes out, what purpose would it serve
to stop warning people that 754 special-value behavior is a x-platform
crapshoot?  Much of it (albeit less so) will remain a crapshoot after
2.5 comes out too.

>>> But first, I'm going to whinge a bit, and lay out some stuff that Tim
>>> at least already knows (and maybe get some stuff wrong, we'll see).
>>>
>>> Floating point standards lay out a number of "conditions": Overflow
>>> (number too large in magnitude to represent), Underflow (non-zero
>>> number to small in magnitude to represent), Subnormal (non-zero number
>>> to small in magnitude to represent in a normalized way), ...

>> The 754 standard has five of them:  underflow, overflow, invalid
>> operation, inexact, and "divide by 0" (which should be understood more
>> generally as a singularity; e.g., divide-by-0 is also appropriate for
>> log(0)).

> OK, the decimal standard has more, which confused me for a bit
> (presumably it has more because it doesn't normalize after each
> operation).

The "conditions" in IBM's decimal standard map, many-to-one, on to a
smaller collection of "signals" in that standard.  It has 8 signals: 
the 5 I named above from 754, plus "clamped", "rounded", and
"subnormal".  Distinctions are excruciatingly subtle; e.g., "rounded"
and "inexact" would be the same thing in 754, but, as you suggest, in
the decimal standard a result can be exact yet also rounded (if it
"rounds away" one or more trailing zeroes), due to the unnormalized
model.

>>> For each condition, it should (at some level) is possible to trap each
>>> condition, or continue in some standard-mandated way (e.g. return 0
>>> for Underflow).

>> 754 requires that, yes.

>>> While ignoring the issue of allowing the user to control this, I do
>>> wish sometimes that Python would make up it's mind about what it does
>>> for each condition.

>> Guido and I agreed long ago that Python "should", by default, raise an
>> exception on overflow, invalid operation, and divide by 0, and "should
>> not", by default, raise an exception on underflow or inexact.

And, I'll add, "should not" on rounded, clamped and subnormal too.

> OK.

OK .

>> Such defaults favor non-expert use.  Experts may or may not be happy
>> with them, so Python "should" also allow changing the set.
 
> Later :)

That's a problem, though.  754 subsets are barely an improvement over
what Python does today:  the designers knew darned well that each
default is going to make some non-trivial group of users horridly
unhappy.  That's why such extensive machinery for detecting signals,
and for trapping or not trapping on signals, is mandated.  That's a
very important part of these standards.

> (In the mean time can we just kill fpectl, please?)

Has it been marked as deprecated yet (entered into the PEP for
deprecated modules, raises deprecation warnings, etc)?  I don't know. 
IMO it should become deprecated, but I don't have time to push that.

>>> There are a bunch of conditions which we shouldn't and don't trap by
>>> default -- Underflow for example.  For the conditions that probably should
>>> result in an exception, there are inconsistencies galore:
>>>
>>> >>> inf = 1e300 * 1e300 # <- Overflow, no exception
>>> >>> nan = inf/inf # <- InvalidOperation, no exception

>> Meaning you're running on a 754 platform whose C runtime arranged to
>> disable the overflow and invalid operation traps.
 
> Isn't that the standard-mandated start up environment?

The 754 standard mandates "non-stop" mode (all traps disabled) at
startup, but who in this chain is _claiming_ to implement the 754
standard?  Your platform C may or may not, and your OS may or may not.

>> You're seeing native HW fp behavior then.

> But anyway, shouldn't we try to raise exceptions in these cases?

I believe Python should raise exceptions in these cases by default,
because, as above, they correspond to the overflow and
invalid-operation signals respectively, and Python should raise
exceptions on the overflow, invalid-operation, and divide-by-0 signals
by default.  But I also believe Python _dare not_ do so unle

Re: math.nroot [was Re: A brief question.]

2005-07-06 Thread Jeff Epler
On Tue, Jul 05, 2005 at 09:49:33PM +0100, Tom Anderson wrote:
> Are there any uses for NaN that aren't met by exceptions?

Sure.  If you can naturally calculate two things at once, but one might
turn out to be a NaN under current rules.

x, y = calculate_two_things()
if isnan(x):
perform_next_step_with_only_y(y)
else:
perform_next_step_with_both(x, y)

Under your scheme, you'd have to write
try:
x, y = calculate_two_things()
except NaNException:
y = calculate_one_thing()
perform_next_step_with_only_y(y)
else:
perform_next_step_with_both(x, y)
and at the very least duplicate the code for calculating 'y', possibly
re-doing a lot of work at runtime too.

Jeff


pgpVUpJh4xufX.pgp
Description: PGP signature
-- 
http://mail.python.org/mailman/listinfo/python-list

Re: math.nroot [was Re: A brief question.]

2005-07-05 Thread Steven D'Aprano
On Tue, 05 Jul 2005 10:10:47 -0500, Terry Hancock wrote:

> I have to mention that the idea of a math package that 
> allows NaN to propagate as though it were a number 
> scares the willies out of me.  God help me if I were to use
> it on something like Engineering where lives might
> depend on the answer being right.

The whole point of propogating NaNs is that they ever go away. Instead of
putting hundreds of tests for error conditions all through your code, and
god help you if you miss some obscure error condition or put it in the
wrong place, you put one test at the very end: is the final result a NaN
or not?

Of course, the point is moot, since the IEEE standard allows you to
specify that errors are signalling or non-signalling (quiet). You can pick
the behaviour that suits the application.

> That'd be like having a math package that allowed,
> say 0/0 = 1 or Inf/Inf = 1.  

If I recall correctly, the IEEE standard requires both of those to return
NaN, which is really the only correct thing to do.


-- 
Steven


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-05 Thread Tom Anderson
On Tue, 5 Jul 2005, Terry Hancock wrote:

> Really, the only *right* thing to do is to raise an exception ASAP after 
> the NaN comes up.

That sounds like a very good idea.

Are there any uses for NaN that aren't met by exceptions?

tom

-- 
[Philosophy] is kind of like being driven behind the sofa by Dr Who - scary, 
but still entertaining. -- Itchyfidget
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-05 Thread Michael Hudson
Tim Peters <[EMAIL PROTECTED]> writes:

> [Tim Peters]
> >> All Python behavior in the presence of infinities, NaNs, and signed
> >> zeroes is a platform-dependent accident, mostly inherited from that
> >> all C89 behavior in the presence of infinities, NaNs, and signed
> >> zeroes is a platform-dependent crapshoot.
>  
> [Michael Hudson]
> > As you may have noticed by now, I'd kind of like to stop you saying
> > this :) -- at least on platforms where doubles are good old-fashioned
> > 754 8-byte values.
> 
> Nope, I hadn't noticed!  I'll stop saying it when it stops being true,
> though .  Note that since there's not even an alpha out for 2.5
> yet, none of the good stuff you did in CVS counts for users yet.

Well, obviously.  OTOH, there's nothing I CAN do that will be useful
for users until 2.5 actually comes out.

> > But first, I'm going to whinge a bit, and lay out some stuff that Tim
> > at least already knows (and maybe get some stuff wrong, we'll see).
> >
> > Floating point standards lay out a number of "conditions": Overflow
> > (number too large in magnitude to represent), Underflow (non-zero
> > number to small in magnitude to represent), Subnormal (non-zero number
> > to small in magnitude to represent in a normalized way), ...
> 
> The 754 standard has five of them:  underflow, overflow, invalid
> operation, inexact, and "divide by 0" (which should be understood more
> generally as a singularity; e.g., divide-by-0 is also appropriate for
> log(0)).

OK, the decimal standard has more, which confused me for a bit
(presumably it has more because it doesn't normalize after each
operation).

> > For each condition, it should (at some level) is possible to trap each
> > condition, or continue in some standard-mandated way (e.g. return 0
> > for Underflow).
> 
> 754 requires that, yes.
> 
> > While ignoring the issue of allowing the user to control this, I do
> > wish sometimes that Python would make up it's mind about what it does
> > for each condition.
> 
> Guido and I agreed long ago that Python "should", by default, raise an
> exception on overflow, invalid operation, and divide by 0, and "should
> not", by default, raise an exception on underflow or inexact.

OK.

> Such defaults favor non-expert use.  Experts may or may not be happy
> with them, so Python "should" also allow changing the set.

Later :)

(In the mean time can we just kill fpectl, please?)

> > There are a bunch of conditions which we shouldn't and don't trap by
> > default -- Underflow for example.  For the conditions that probably should
> > result in an exception, there are inconsistencies galore:
> 
> > >>> inf = 1e300 * 1e300 # <- Overflow, no exception
> > >>> nan = inf/inf # <- InvalidOperation, no exception
> 
> Meaning you're running on a 754 platform whose C runtime arranged to
> disable the overflow and invalid operation traps.

Isn't that the standard-mandated start up environment?

> You're seeing native HW fp behavior then.

But anyway, shouldn't we try to raise exceptions in these cases?  I
don't think it's a particularly good idea to try to utilize the fp
hardware's ability to do this at this stage, btw, but to add some kind
of check after each operation.

> > >>> pow(1e100, 100) <- Overflow, exception
> > Traceback (most recent call last):
> >  File "", line 1, in ?
> > OverflowError: (34, 'Numerical result out of range')
> > >>> math.sqrt(-1) # <- InvalidOperation, exception
> > Traceback (most recent call last):
> >  File "", line 1, in ?
> > ValueError: math domain error
> 
> Unlike the first two examples, these call libm functions.

And the user cares about this why?

> Then it's a x-platform crapshoot whether and when the libm functions
> set errno to ERANGE or EDOM, and somewhat of a mystery whether it's
> better to reproduce what the native libm considers to be "an error",
> or try to give the same results across platforms.  Python makes a
> weak attempt at the latter.

Well, you can at least be pretty sure that an infinite result is the
result of an overflow condition, I guess.

> > At least we're fairly consistent on DivisionByZero...
> 
> When it's a division by 0, yes.  It's cheap and easy to test for that.
>  However, many expert uses strongly favor getting back an infinity
> then instead, so it's not good that Python doesn't support a choice
> about x/0.

Indeed.  But I'd rather work on non-settable predictability first.

> > If we're going to trap Overflow consistently, we really need a way of
> > getting the special values reliably -- which is what pep 754 is about,
> > and its implementation may actually work more reliably in 2.5 since my
> > recent work...
> 
> I don't know what you have in mind.  

Well, the reason I headbutted into this stuff again recently was
writing (grotty) string to float parsing code for PyPy.  If you write
(where 'e' is the exponent parsed from, say '1e309'):

while e > 0:
result *= 10
e -= 1

you get an infinite result in the large e case.  If instead you wri

Re: math.nroot [was Re: A brief question.]

2005-07-05 Thread Terry Hancock
On Sunday 03 July 2005 10:47 pm, Steven D'Aprano wrote:
> Any floating point package that supports the IEEE 
> standard should give you a test to see if a float 
> represents a NaN. That's what you need. You certainly 
> can't rely on "x == SOME_NAN" because there are 254 
> different NaNs.
> 
> There is no sensible reason to test equality of NaNs. 
> It is logically nonsense to say that one NaN is equal 
> to another, as such a thing implies contradictions like 
> -1==-2. If you support IEEE, you will have a test for 
> NaNs, so you can detect them when you need to.

I have to mention that the idea of a math package that 
allows NaN to propagate as though it were a number 
scares the willies out of me.  God help me if I were to use
it on something like Engineering where lives might
depend on the answer being right.

That'd be like having a math package that allowed,
say 0/0 = 1 or Inf/Inf = 1.  It's not hard at all to come
up with dozens of problems for which that is the WRONG
guess -- getting an actual answer for dividing two
infinities requires using limits and calculus.  The reason
Inf/Inf isn't defined is that it can actually be just about
any number --- finite or infinite.

I can seriously imagine structures breaking and collapsing
because they were designed using such a package, and
a NaN was generated and missed somewhere.

Really, the only *right* thing to do is to raise an exception
ASAP after the NaN comes up.

On a more practical note, *is* there a isNaN() function? Seems
like it ought to be in the math module.   Looks like you have
to do it through "fpectl" as things stand.

Is anyone else bothered that "math" and "cmath" are in the
"Miscellaneous Services" section of the LR? Seems like we
ought to get Numeric and/or Numarray and group all of
these in a separate "Math & Science" section.

--
Terry Hancock ( hancock at anansispaceworks.com )
Anansi Spaceworks  http://www.anansispaceworks.com

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-05 Thread Tim Peters
[Tim Peters]
>> All Python behavior in the presence of infinities, NaNs, and signed
>> zeroes is a platform-dependent accident, mostly inherited from that
>> all C89 behavior in the presence of infinities, NaNs, and signed
>> zeroes is a platform-dependent crapshoot.
 
[Michael Hudson]
> As you may have noticed by now, I'd kind of like to stop you saying
> this :) -- at least on platforms where doubles are good old-fashioned
> 754 8-byte values.

Nope, I hadn't noticed!  I'll stop saying it when it stops being true,
though .  Note that since there's not even an alpha out for 2.5
yet, none of the good stuff you did in CVS counts for users yet.

> But first, I'm going to whinge a bit, and lay out some stuff that Tim
> at least already knows (and maybe get some stuff wrong, we'll see).
>
> Floating point standards lay out a number of "conditions": Overflow
> (number too large in magnitude to represent), Underflow (non-zero
> number to small in magnitude to represent), Subnormal (non-zero number
> to small in magnitude to represent in a normalized way), ...

The 754 standard has five of them:  underflow, overflow, invalid
operation, inexact, and "divide by 0" (which should be understood more
generally as a singularity; e.g., divide-by-0 is also appropriate for
log(0)).

> For each condition, it should (at some level) is possible to trap each
> condition, or continue in some standard-mandated way (e.g. return 0
> for Underflow).

754 requires that, yes.

> While ignoring the issue of allowing the user to control this, I do
> wish sometimes that Python would make up it's mind about what it does
> for each condition.

Guido and I agreed long ago that Python "should", by default, raise an
exception on overflow, invalid operation, and divide by 0, and "should
not", by default, raise an exception on underflow or inexact.  Such
defaults favor non-expert use.  Experts may or may not be happy with
them, so Python "should" also allow changing the set.

> There are a bunch of conditions which we shouldn't and don't trap by
> default -- Underflow for example.  For the conditions that probably should
> result in an exception, there are inconsistencies galore:

> >>> inf = 1e300 * 1e300 # <- Overflow, no exception
> >>> nan = inf/inf # <- InvalidOperation, no exception

Meaning you're running on a 754 platform whose C runtime arranged to
disable the overflow and invalid operation traps.  You're seeing
native HW fp behavior then.

> >>> pow(1e100, 100) <- Overflow, exception
> Traceback (most recent call last):
>  File "", line 1, in ?
> OverflowError: (34, 'Numerical result out of range')
> >>> math.sqrt(-1) # <- InvalidOperation, exception
> Traceback (most recent call last):
>  File "", line 1, in ?
> ValueError: math domain error

Unlike the first two examples, these call libm functions.  Then it's a
x-platform crapshoot whether and when the libm functions set errno to
ERANGE or EDOM, and somewhat of a mystery whether it's better to
reproduce what the native libm considers to be "an error", or try to
give the same results across platforms.  Python makes a weak attempt
at the latter.

> At least we're fairly consistent on DivisionByZero...

When it's a division by 0, yes.  It's cheap and easy to test for that.
 However, many expert uses strongly favor getting back an infinity
then instead, so it's not good that Python doesn't support a choice
about x/0.

> If we're going to trap Overflow consistently, we really need a way of
> getting the special values reliably -- which is what pep 754 is about,
> and its implementation may actually work more reliably in 2.5 since my
> recent work...

I don't know what you have in mind.  For example, checking the result
of x*y to see whether it's an infinity is not a reliable way to detect
overflow, and it fails in more than one way (e.g., one of the inputs
may have been an infinity (in which case OverflowError is
inappropriate), and overflow doesn't always result in an infinity
either (depends on the rounding mode in effect)).

> On the issue of platforms that start up processes with traps enabled,
> I think the correct solution is to find the incantation to turn them
> off again and use that in Py_Initialize(), though that might upset
> embedders.

Hard to know.  Python currently has a hack to disable traps on
FreeBSD, in python.c's main().
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-05 Thread Michael Hudson
Tim Peters <[EMAIL PROTECTED]> writes:

> All Python behavior in the presence of infinities, NaNs, and signed
> zeroes is a platform-dependent accident, mostly inherited from that
> all C89 behavior in the presence of infinities, NaNs, and signed
> zeroes is a platform-dependent crapshoot.

As you may have noticed by now, I'd kind of like to stop you saying
this :) -- at least on platforms where doubles are good old-fashioned
754 8-byte values.

But first, I'm going to whinge a bit, and lay out some stuff that Tim
at least already knows (and maybe get some stuff wrong, we'll see).

Floating point standards lay out a number of "conditions": Overflow
(number too large in magnitude to represent), Underflow (non-zero
number to small in magnitude to represent), Subnormal (non-zero number
to small in magnitude to represent in a normalized way), ...

For each condition, it should (at some level) is possible to trap each
condition, or continue in some standard-mandated way (e.g. return 0
for Underflow).

While ignoring the issue of allowing the user to control this, I do
wish sometimes that Python would make up it's mind about what it does
for each condition.  There are a bunch of conditions which we
shouldn't and don't trap by default -- Underflow for example.  For the
conditions that probably should result in an exception, there are
inconsistencies galore:

>>> inf = 1e300 * 1e300 # <- Overflow, no exception
>>> nan = inf/inf # <- InvalidOperation, no exception
>>> pow(1e100, 100) <- Overflow, exception
Traceback (most recent call last):
  File "", line 1, in ?
OverflowError: (34, 'Numerical result out of range')
>>> math.sqrt(-1) # <- InvalidOperation, exception
Traceback (most recent call last):
  File "", line 1, in ?
ValueError: math domain error

At least we're fairly consistent on DivisionByZero...

If we're going to trap Overflow consistently, we really need a way of
getting the special values reliably -- which is what pep 754 is about,
and its implementation may actually work more reliably in 2.5 since my
recent work...

On the issue of platforms that start up processes with traps enabled,
I think the correct solution is to find the incantation to turn them
off again and use that in Py_Initialize(), though that might upset
embedders.

Cheers,
mwh

-- 
   rasterman is the millionth monkey
-- from Twisted.Quotes
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-04 Thread Steven D'Aprano
On Mon, 04 Jul 2005 15:35:56 +0100, Tom Anderson wrote:

>>> Also, would it be a good idea for (-1.0) ** 0.5 to evaluate to 1.0j? It
>>> seems a shame to have complex numbers in the language and then miss this
>>> opportunity to use them!
>>
>> It's generally true in Python that complex numbers are output only if 
>> complex numbers are input or you explicitly use a function from the 
>> cmath module. [...] The presumption is that a complex result is more 
>> likely the result of program error than intent for most applications. 
>> The relative handful of programmers who expect complex results can get 
>> them easily, though.
> 
> A reasonable presumption.
> 
> I always got really wound up that the calculator i had at school had this 
> behaviour too, *even in complex number mode*! Come to think of it, i don't 
> think it could do roots of imaginary numbers at all. However, python is 
> not a calculator.

Of course it is :-)

py> 1+2
3

It even works with complex numbers:

py> print (-1+0j)**0.5
(6.12303176911e-17+1j)

although you have to watch out for those rounding errors in floating 
point.

py> import cmath
py> cmath.sqrt(-1)
1j

-- 
Steven

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-04 Thread James Dennett
Steven D'Aprano wrote:

> James Dennett wrote:
> 
>> > Yes: 5^2 + -2^2 is 29, however you write it.
>>
>> *If* you take -2 as a number, but not if you take the number
>> as 2 and the unary minus as an operator with lower precedence
>> than exponentiation.
> 
> 
> [snip]
> 
>> Not in this respect.  However, the question is whether that's
>> a unary -, which binds lower than exponentiation in most systems,
>> or part of the negative number minus 2.
> 
> 
> In Python, all numbers are positive. -2 is a unary minus in front of 2.

Indeed, as I hoped was clear from the rest of my post.  When
we're discussing what the rules of Python *should* be, however,
it's necessary to step back and not assume that the rules of
Python are "right", whatever we might mean by that.

I was illustrating that the choice made by Python in this
respect, i.e., of viewing "-2" as an expression where unary
minus applies to the number 2, naturally leads to
5**2 + -2**2 being evaluated as 21 (because of the precedence
of unary minus), whereas taking "-2" as a number would lead
to the answer 29 (which is not what Python gives).

That said, Python's choice is consistent with conventional
mathematical notation, which is one reason not to lex -2 as
a number in a language with an infix exponentiation operator.

-- James
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-04 Thread Tom Anderson
On Sun, 3 Jul 2005, Tim Peters wrote:

> [Tom Anderson]
>> So, is there a way of generating and testing for infinities and NaNs
>> that's portable across platforms and versions of python?
>
> Not that I know of, and certainly no simple way.
>
>> If not, could we perhaps have some constants in the math module for them?
>
> See PEP 754 for this.

Looks perfect.

>>> Read the manual for the precedence rules.  -x**y groups as -(x**y). 
>>> -1.0 is the correct answer.  If you intended (-x)**y, then you need to 
>>> insert parentheses to force that order.
>
>> So i see. Any idea why that precedence order was chosen? It goes against
>> conventional mathematical notation, as well as established practice in
>> other languages.
>
> Eh?  For example, Fortran and Macsyma also give exponentiation higher 
> precedence than unary minus.  From my POV, Python's choice here was 
> thoroughly conventional.

I guess you're right. What really threw me is that in all the other 
languages i know (which is not many, i admit), -1 is a literal -1, not a 
literal 1 plus a unary minus.

>> Also, would it be a good idea for (-1.0) ** 0.5 to evaluate to 1.0j? It
>> seems a shame to have complex numbers in the language and then miss this
>> opportunity to use them!
>
> It's generally true in Python that complex numbers are output only if 
> complex numbers are input or you explicitly use a function from the 
> cmath module. [...] The presumption is that a complex result is more 
> likely the result of program error than intent for most applications. 
> The relative handful of programmers who expect complex results can get 
> them easily, though.

A reasonable presumption.

I always got really wound up that the calculator i had at school had this 
behaviour too, *even in complex number mode*! Come to think of it, i don't 
think it could do roots of imaginary numbers at all. However, python is 
not a calculator.

tom

-- 
A military-industrial illusion of democracy
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-04 Thread Tom Anderson
On Sun, 3 Jul 2005, Dennis Lee Bieber wrote:

> On Sun, 3 Jul 2005 20:53:22 +0100, Tom Anderson <[EMAIL PROTECTED]>
> declaimed the following in comp.lang.python:
>
>>2
>> -1
>>
>> Evaluates to -1?
>
>   But what do you expect, say
>
>   2
> -X
>
> to evaluate as? (-X)^2 or -(X^2)
>
>   I'd expect the latter...

I think you've got me there.

> I see the problem here as an assumption that "-1" is an entity in its 
> own right, and not an operation of negating a "1", whereas "-X" is the 
> entity "X" being negated.

I think you're entirely correct. I'm not entirely sure that that 
assumption is wrong, but never mind.

Anyway, it looks like i should really be filing a bug report with the 
International Mathematical Union about this, rather than whingeing about 
it here.

tom

-- 
A military-industrial illusion of democracy
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-04 Thread George Sakkis
"Steven D'Aprano" <[EMAIL PROTECTED]> wrote:

> But it doesn't make sense to say that two flags are equal:
>
> keep_processing = True
> more_reading_needed = True
> while more_reading_needed and keep_processing:
>  get_more_records()
>  process_records()
> if not keep_processing:
>  print "User clicked Cancel"
>
> What does it mean to say that the flag done_processing
> is equal to the flag more_reading_needed? (That is not
> the same question as asking if the two flags have the
> same value.)

Huh ? Equality *is* the answer to whether two "things" (flags or
whatever) have the same value or not. What else could it be ? Certainly
not whether they are *the same*; you have the 'is' operator for
checking identity. In any case, "done_processing ==
more_reading_needed" is perfectly valid and most people would agree
that if the result is True, "done_processing" and "more_reading_needed"
are equal.

> It gets worse. Consider this example of "logic":
>
> x = log(-5)  # a NaN
> y = log(-2)  # the same NaN
> x == y  # you want this to be true for NaNs
>
> Then:
>
> # compare x and y directly
> log(-5) == log(-2)
> # if x == y then exp(x) == exp(y) for all x, y
> exp(log(-5)) == exp(log(-2))
> -5 == -2

Such paradox cases can be avoided if the only operations defined for
NaNs are equality/inequality; all others yield NaN too. That is,
exp(NaN) is NaN, as it is log(NaN), 3**NaN / 5i and so on. Think of NaN
as a black hole that absorbs and assimilates what falls into it, so
log(-5) and log(-2) are just NaN, they lose their "identity" as two
distinct things, "log(-5)" and "log(-2)".

> > Similarly, if z=0/0, z would also be invalid, but
> > different from x and y, since it is the result of a different invalid
> > operation. This brings us to the many-NaN situation.
>
> The problem is, the many NaNs in the IEEE standard (or
> at least Apple's implementation of it) refer to _kinds_
> of NaNs, not NaNs themselves.
>
> log(-2) is not the same "not a number" as log(-2.0001),
> or log(-2.3). They might be the same "kind" of failure,
> but that's it.

That's absolutely fine; as long as two "things" are invalid and they're
invalid for the same reason ("kind of failure"), they are equal to me.

> Having given reasons why it is utterly bogus to be
> comparing NaNs for equality, I will say this.
> Practicality beats purity. If you can demonstrate a
> good usage case for testing equality with NaNs, I will
> accept that it is a good thing to do.
>
> if x in (SOME_NAN, SOME_OTHER_NAN, ANOTHER_NAN, \
>  YET_ANOTHER_NAN, AND_ANOTHER_NAN, ..., \
>  # 240+ more NaNs listed
>  ALMOST_FINISHED_NOW, LAST_NAN):
>  print "Calculation failed!"
>
> is _not_ a good usage case, since it is best handled with:
>
> if isNan(x):  # handled by the floating point package
>  print "Calculation failed!"

Agreed on that, if all you need to know is if the outcome of an
expression is valid or not. But since a NaN can be thought of as "a
flag representing the fact that an error occurred", as you mentioned,
it makes sense in practice to ask whether two errors are of the same
kind, e.g. for handling them differently. If I understood correctly,
your objection is using the equality operator '==' with these semantics
for NaNs. I would say that it's a reasonable choice for "practicality
beats purity" reasons, if nothing else.

George

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-04 Thread OKB (not okblacke)
Tom Anderson wrote:

> Yes. However, it's an excellent reason why python's precedence
> rules are wrong - in conventional mathematical notation, the unary
> minus, used to denote the sign of a literal number, does indeed
> have higher precedence than exponentiation: -1^2 evaluates to 1,
> not -1. 

This isn't true.  The "unary minus operator" is just a shorthand 
for multiplication by -1.  As such, it has the same operator precedence 
as multiplication.

-- 
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead.  Go, instead, where there is
no path, and leave a trail."
--author unknown
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Steven D'Aprano
Tom Anderson wrote about NaNs:

> > (Remember, a NaN is just an illusionary placeholder, not a number.)
> 
> If you think it's illusionary, i invite you to inspect the contents of 
> my variables - i have a real, live NaN trapped in one of them!

No you don't. You have a flag that says "This 
calculation failed" in your variable.

[snip]

> Yes. It may not be mathematically pure (although i argue that it is, in 
> fact, as long as you don't think of floats as being real numbers), it is 
> practical, and practicality beats purity.

But then:

>> But, apart from testing whether a float is a NaN, why would you ever 
>> want to do an equality test?
> 
> 
> By definition, never. Isn't that usage reason enough?

So, what you are saying is that you don't actually have 
a usage case for testing equality for NaNs.

Any floating point package that supports the IEEE 
standard should give you a test to see if a float 
represents a NaN. That's what you need. You certainly 
can't rely on "x == SOME_NAN" because there are 254 
different NaNs.

There is no sensible reason to test equality of NaNs. 
It is logically nonsense to say that one NaN is equal 
to another, as such a thing implies contradictions like 
-1==-2. If you support IEEE, you will have a test for 
NaNs, so you can detect them when you need to.

Problem solved.

> 
>> The only usage case I can think of is would be something like this:
>>
>> def isNaN(x):
>>return x == SOME_KNOWN_NAN
>>
>> But that won't work, because there are lots of different NaNs. 254 of 
>> them, or twice that if you include signed NaNs (which you shouldn't, 
>> but you do have to allow for them in equality testing).
> 
> 
> Ah, well. There we have the question of whether python should implement 
> full-blown IEEE arithmetic. This is somewhat heretical, but i think it 
> shouldn't; i think it would be much better to adopt Java's noddy-IEEE 
> approach, where there's exactly one NaN (although with well-behaved 
> equality comparison). I realise this isn't going to happen, though.

Well-behaved equality comparison means that nan == nan 
returns false. Otherwise you have contradictions like this:

x = log(-1)  # one flavour of NaN
y = asin(2)  # a different flavour of NaN

log(-1) == asin(2)
sin(log(-1)) == 2
sin(NaN) == 2
NaN == 2

Contradiction.




[snip]

> I am utterly baffled. Three people so far have told me that 
> exponentiation has higher precedence than unary minus *in conventional 
> notation*. 

Yes.

> Are you really telling me that you think this expression:
> 
>   2
> -1
> 
> Evaluates to -1?

Of course it does. That's why mathematicians use

(-1)^n

for series where the sign of each term alternates, 
instead of -1^n which would just give -1, -1, -1, ...


-- 
Steven

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Steven D'Aprano
James Dennett wrote:

> > Yes: 5^2 + -2^2 is 29, however you write it.
> 
> *If* you take -2 as a number, but not if you take the number
> as 2 and the unary minus as an operator with lower precedence
> than exponentiation.

[snip]

> Not in this respect.  However, the question is whether that's
> a unary -, which binds lower than exponentiation in most systems,
> or part of the negative number minus 2.

In Python, all numbers are positive. -2 is a unary 
minus in front of 2.

-- 
Steven.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Steven D'Aprano
George Sakkis wrote:
> "Tom Anderson" <[EMAIL PROTECTED]> wrote:
> 
> 
>>>But NaNs are _not_ things.
>>
>>I disagree. A NaN _is_ a thing; it's not a floating-point number, for
>>sure, but it is a symbol which means "there is no answer", or "i don't
>>know", and as such, it should follow the universal rules which apply to
>>all things.
> 
> 
> It seems that the standard semantics of NaN is closer to NULL values in
> ANSI SQL, that is "unknown", "not available". In this sense, if you
> have two 'things' you don't know, you can't say they are equal simply
> because you don't know them !

It isn't that they are unknown. They don't exist, so 
you can't compare them! The bit-patterns that represent 
NaNs should not be thought of as "the answer to the 
calculation", but merely "a flag representing the fact 
that an error occurred".

The nice thing is that the flag can propogate through 
your calculations, so you can defer testing for an 
error condition until the very end, but it is not a value.

When you think of NaNs as flags, the question of 
equality doesn't apply. You can compare two flags bit 
by bit to see if they have the same bit pattern, and 
that's what the isNan() function is for: test if a 
float has a bit pattern that represents a NaN.

But it doesn't make sense to say that two flags are equal:

keep_processing = True
more_reading_needed = True
while more_reading_needed and keep_processing:
 get_more_records()
 process_records()
if not keep_processing:
 print "User clicked Cancel"

What does it mean to say that the flag done_processing 
is equal to the flag more_reading_needed? (That is not 
the same question as asking if the two flags have the 
same value.)



>>>Since INF-INF doesn't have an answer, we can't do this:
>>>
>>>x = inf - inf
>>>y = inf - inf
>>>
>>>and expect that x == y.
>>
>>I think we can. Both x and y have the same value, a value of
>>indeterminacy. NaN is a rigidly defined value of doubt and uncertainty!
> 
> 
> In this case, however, I would agree. x and y above are not assigned a
> label of 'unknown'; they are derived from an operation among valid
> *known* values, so NaN here means 'invalid' rather than 'unknown'.It
> makes sense to have x==y, because x and y are the outcome of the *same*
> invalid operation.

This is incorrect. Mathematically, you CAN'T say:

x = INF - INF
y = INF - INF

therefore x = y. This is just _wrong_. Mathematically, 
x and y don't exist, so they can't be equal since 
equality is only defined for things which exist.

It gets worse. Consider this example of "logic":

x = log(-5)  # a NaN
y = log(-2)  # the same NaN
x == y  # you want this to be true for NaNs

Then:

# compare x and y directly
log(-5) == log(-2)
# if x == y then exp(x) == exp(y) for all x, y
exp(log(-5)) == exp(log(-2))
-5 == -2


> Similarly, if z=0/0, z would also be invalid, but
> different from x and y, since it is the result of a different invalid
> operation. This brings us to the many-NaN situation.

The problem is, the many NaNs in the IEEE standard (or 
at least Apple's implementation of it) refer to _kinds_ 
of NaNs, not NaNs themselves.

log(-2) is not the same "not a number" as log(-2.0001), 
or log(-2.3). They might be the same "kind" of failure, 
but that's it.

You can't even say that log(-2) == log(-2), because 
equality is only defined for numbers, not "no such thing".

Having given reasons why it is utterly bogus to be 
comparing NaNs for equality, I will say this. 
Practicality beats purity. If you can demonstrate a 
good usage case for testing equality with NaNs, I will 
accept that it is a good thing to do.

if x in (SOME_NAN, SOME_OTHER_NAN, ANOTHER_NAN, \
 YET_ANOTHER_NAN, AND_ANOTHER_NAN, ..., \
 # 240+ more NaNs listed
 ALMOST_FINISHED_NOW, LAST_NAN):
 print "Calculation failed!"

is _not_ a good usage case, since it is best handled with:

if isNan(x):  # handled by the floating point package
 print "Calculation failed!"


-- 
Steven.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread George Sakkis
"Tom Anderson" <[EMAIL PROTECTED]> wrote:

> > But NaNs are _not_ things.
>
> I disagree. A NaN _is_ a thing; it's not a floating-point number, for
> sure, but it is a symbol which means "there is no answer", or "i don't
> know", and as such, it should follow the universal rules which apply to
> all things.

It seems that the standard semantics of NaN is closer to NULL values in
ANSI SQL, that is "unknown", "not available". In this sense, if you
have two 'things' you don't know, you can't say they are equal simply
because you don't know them !

> > Since INF-INF doesn't have an answer, we can't do this:
> >
> > x = inf - inf
> > y = inf - inf
> >
> > and expect that x == y.
>
> I think we can. Both x and y have the same value, a value of
> indeterminacy. NaN is a rigidly defined value of doubt and uncertainty!

In this case, however, I would agree. x and y above are not assigned a
label of 'unknown'; they are derived from an operation among valid
*known* values, so NaN here means 'invalid' rather than 'unknown'. It
makes sense to have x==y, because x and y are the outcome of the *same*
invalid operation. Similarly, if z=0/0, z would also be invalid, but
different from x and y, since it is the result of a different invalid
operation. This brings us to the many-NaN situation.

George

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Tim Peters
...

[Tom Anderson]
> So, is there a way of generating and testing for infinities and NaNs
> that's portable across platforms and versions of python?

Not that I know of, and certainly no simple way.

> If not, could we perhaps have some constants in the math module for them?

See PEP 754 for this.

...

>> Read the manual for the precedence rules.  -x**y groups as -(x**y). -1.0
>> is the correct answer.  If you intended (-x)**y, then you need to insert
>> parentheses to force that order.

> So i see. Any idea why that precedence order was chosen? It goes against
> conventional mathematical notation, as well as established practice in
> other languages.

Eh?  For example, Fortran and Macsyma also give exponentiation higher
precedence than unary minus.  From my POV, Python's choice here was
thoroughly conventional.

> Also, would it be a good idea for (-1.0) ** 0.5 to evaluate to 1.0j? It
> seems a shame to have complex numbers in the language and then miss this
> opportunity to use them!

It's generally true in Python that complex numbers are output only if
complex numbers are input or you explicitly use a function from the
cmath module.  For example,

>>> import math, cmath
>>> math.sqrt(-1)
Traceback (most recent call last):
  File "", line 1, in ?
ValueError: math domain error
>>> cmath.sqrt(-1)
1j

The presumption is that a complex result is more likely the result of
program error than intent for most applications.  The relative handful
of programmers who expect complex results can get them easily, though.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread James Dennett
Tom Anderson wrote:

> On Sun, 3 Jul 2005, George Sakkis wrote:
> 
>> "Tom Anderson" <[EMAIL PROTECTED]> wrote:
>>
> And finally, does Guido know something about arithmetic that i 
> don't, or
> is this expression:
>
> -1.0 ** 0.5
>
> Evaluated wrongly?


 No, it is evaluated according to the rules of precedence. It is
 equivalent to -(1.0**0.5). You are confusing it with (-1.0)**0.5 which
 fails as expected.
>>>
>>>
>>> Ah. My mistake. I submit that this is also a bug in python's grammar.
>>> There's probably some terribly good reason for it, though.
>>
>>
>> How about 'conformance with standard mathematic notation', does this 
>> count for a terribly good reason?
> 
> 
> Yes. However, it's an excellent reason why python's precedence rules are 
> wrong - in conventional mathematical notation, the unary minus, used to 
> denote the sign of a literal number, does indeed have higher precedence 
> than exponentiation: -1^2 evaluates to 1, not -1.

No... that would mean that -x^2 == x^2 always, and we certainly
expect the lhs to always be negative or zero (for real x), and
the rhs to be non-negative.  Unary minus has lower precendence
than exponentiation, in conventional mathematics.  You'll often
see (-1)^n written in mathematics when we want the alternating
sequence +1, -1, +1, -1, ..., as -1^n wouldn't do it (giving
-1, -1, -1, -1).  -1^n evaluates to -1, for all non-zero integral
n.

> 
>> What would one expect to be the result of 5^2 - 2^2, 29 or 21?
> 
> 
> 21.

True, unambiguously; there are no negative numbers involved
at any time, just a simple binary minus.

> 
>> Would you expect 5^2 + - 2^2 to be different, even if you write it as 
>> 5^2 + -2 ^ 2 ?
> 
> 
> Yes: 5^2 + -2^2 is 29, however you write it.

*If* you take -2 as a number, but not if you take the number
as 2 and the unary minus as an operator with lower precedence
than exponentiation.

> 
>> White space is not significant in math AFAIK ;-)
> 
> 
> No, but there's a very big difference between unary and binary minus.

Not in this respect.  However, the question is whether that's
a unary -, which binds lower than exponentiation in most systems,
or part of the negative number minus 2.

-- James
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Tom Anderson
On Mon, 4 Jul 2005, Steven D'Aprano wrote:

> On Sun, 03 Jul 2005 15:46:35 +0100, Tom Anderson wrote:
>
>> I think there would be a lot less confusion over the alleged inaccuracy of
>> floating point if everyone wrote in hex - indeed, i believe that C99 has
>> hex floating-point literals. C has always been such a forward-thinking
>> language!
>
> No, all that would do is shift the complaint from "Python has a bug when
> you divide 10 into 1.0" to "Python has a bug when you convert 0.1 into hex".

Ah, but since the programmer would have to do that conversion themself, 
they wouldn't be able to blame python got it!

>>> But this works:
>>>
>>> py> inf = float("inf")
>>> py> inf
>>> inf
>>
>> True. Still, i'd rather not have to rely on string parsing to generate a
>> fairly fundamental arithmetic quantity.
>
> What happens when your Python script is running on a platform that can
> deal with 1e300*1e300 giving 1e600 without overflow?

Then i lose.

> Okay, maybe no such platform exists today (or does it?), but it could 
> exist, and your code will fail on those systems.
>
> I believe that the IEEE standard specifies that float("inf") should give
> an infinity, just as float("0.0") should give a zero.

I think it's been pointed out that this fails on (some versions of?) 
windows.

> For production code, I'd wrap float("inf") in a try...except and only 
> fall back on your method if it raised an exception, and then I'd 
> actually test that your result was a real inf (eg by testing that 
> inf+inf=inf).

Okay, let's try this ...

def mkinf():
try:
return float("inf")
except ValueError:
x = 1e300
while ((x + x) != x):
x = x * x
return x

inf = mkinf()

Is that a portable solution?

 The IEEE spec actually says that (x == nan) should be *false* for 
 every x, including nan. I'm not sure if this is more or less stupid 
 than what python does!
>>>
>>> Well, no, the IEEE standard is correct. NaNs aren't equal to anything, 
>>> including themselves, since they aren't numbers.
>>
>> I don't buy that. Just because something isn't a number doesn't mean it
>> can't be equal to something else, does it? I mean, we even say x == None
>> if x is indeed None.
>
> Yes, but None does equal None, since there is only one None, and by 
> definition, a thing is equal to itself.

Yes.

> But NaNs are _not_ things.

I disagree. A NaN _is_ a thing; it's not a floating-point number, for 
sure, but it is a symbol which means "there is no answer", or "i don't 
know", and as such, it should follow the universal rules which apply to 
all things.

> That is the whole point! Yes, we _represent_ INF-INF as a particular 
> bit-pattern and call it NaN, but mathematically subtracting infinity 
> from infinity is not defined. There is no answer to the question "what 
> is infinity subtracted from infinity?".

There is a value at large in my programs, represented however, meaning 
whatever, and with whatever name, and it should follow the same 
fundamental rules as every single other value in the entire programmatic 
universe. Yes, NaN is a special case, but special cases aren't special 
enough to break the rules.

> We pretend that the answer is NaN, but that isn't right. The NaN is just 
> there as a placeholder for "there is no answer", so that we don't have 
> to sprinkle our code with a thousand and one tests.

In the same way as None is a placeholder for "there is no thing". These 
placeholders are themselves things!

> Since INF-INF doesn't have an answer, we can't do this:
>
> x = inf - inf
> y = inf - inf
>
> and expect that x == y.

I think we can. Both x and y have the same value, a value of 
indeterminacy. NaN is a rigidly defined value of doubt and uncertainty!

>> Moreover, this freaky rule about NaNs means that this is an exception 
>> to the otherwise absolutely inviolate law that x == x.
>
> Yes. So what? Remove the NaN shorthand:
>
> "The non-existent answer to this question is the same non-existent answer
> to this other question."

Make sense to me.

> It doesn't make sense to say that a non-thing is equal to anything -- even
> to itself, since itself doesn't exist.
>
> (Remember, a NaN is just an illusionary placeholder, not a number.)

If you think it's illusionary, i invite you to inspect the contents of my 
variables - i have a real, live NaN trapped in one of them!

>> I'd rather have that simple, fundamental logical consistency than some IEEE
>> rocket scientist's practical-value-free idea of mathematical consistency.
>
> Ah, from a _programmer's_ perspective, there is an argument that the 
> simplicity of just testing NaNs with equality outweighs the logical 
> silliness of doing such a thing.

Yes. It may not be mathematically pure (although i argue that it is, in 
fact, as long as you don't think of floats as being real numbers), it is 
practical, and practicality beats purity.

> But, apart from testing 

Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Tom Anderson
On Sun, 3 Jul 2005, Tim Peters wrote:

> [Fredrik Johansson]
>
 I'd rather like to see a well implemented math.nthroot. 64**(1/3.0)
 gives 3.9996, and this error could be avoided.
>
> [Steven D'Aprano]
>> math.exp(math.log(64)/3.0)
>>> 4.0
>>>
>>> Success!!!
>
> None of this generalizes usefully -- these are example-driven
> curiousities.

I was afraid of that. Thanks for shedding some light on it, though.

>> YES! This is something that winds me up no end; as far as i can tell,
>> there is no clean programmatic way to make an inf or a NaN;
>
> All Python behavior in the presence of infinities, NaNs, and signed 
> zeroes is a platform-dependent accident, mostly inherited from that all 
> C89 behavior in the presence of infinities, NaNs, and signed zeroes is a 
> platform-dependent crapshoot.

Okay. That's a shame.

>> in code i write which cares about such things, i have to start:
>>
>> inf = 1e300 ** 1e300
>> nan = inf - inf
>
> That would be much more portable (== would do what you intended by 
> accident on many more platforms) if you used multiplication instead of 
> exponentiation in the first line.

Yes - that's what i meant to write, but i must have got carried away with 
the asterisks. Sorry about that.

>> And then god forbid i should actually want to test if a number is NaN,
>> since, bizarrely, (x == nan) is true for every x; instead, i have to
>> write:
>>
>> def isnan(x):
>>return (x == 0.0) and (x == 1.0)
>
> The result of that is a platform-dependent accident too.  Python 2.4
> (but not eariler than that) works hard to deliver _exactly_ the same
> accident as the platform C compiler delivers, and at least NaN
> comparisons work "as intended" (by IEEE 754) in 2.4 under gcc and MSVC
> 7.1 (because those C implementations treat NaN comparisons as intended
> by IEEE 754; note that MSVC 6.0 did not):
>
> So at the Python level you can do "x != x" to see whether x is a NaN
> in 2.4+(assuming that works in the C with which Python was compiled;
> it does under gcc and MSVC 7.1).

I see. I have to confess that i'm using 2.3.

So, is there a way of generating and testing for infinities and NaNs 
that's portable across platforms and versions of python? If not, could we 
perhaps have some constants in the math module for them? math.inf and 
math.nan should do nicely (although there is the question of just _which_ 
nan that should be ...). It wouldn't help with old versions of python, but 
it'd solve the problem for the future.

>> or is this expression:
>>
>> -1.0 ** 0.5
>>
>> Evaluated wrongly?
>
> Read the manual for the precedence rules.  -x**y groups as -(x**y). -1.0 
> is the correct answer.  If you intended (-x)**y, then you need to insert 
> parentheses to force that order.

So i see. Any idea why that precedence order was chosen? It goes against 
conventional mathematical notation, as well as established practice in 
other languages.

Also, would it be a good idea for (-1.0) ** 0.5 to evaluate to 1.0j? It 
seems a shame to have complex numbers in the language and then miss this 
opportunity to use them!

tom

-- 
When you mentioned INSERT-MIND-INPUT ... did they look at you like this?
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Tom Anderson
On Sun, 3 Jul 2005, George Sakkis wrote:

> "Tom Anderson" <[EMAIL PROTECTED]> wrote:
>
 And finally, does Guido know something about arithmetic that i don't, or
 is this expression:

 -1.0 ** 0.5

 Evaluated wrongly?
>>>
>>> No, it is evaluated according to the rules of precedence. It is
>>> equivalent to -(1.0**0.5). You are confusing it with (-1.0)**0.5 which
>>> fails as expected.
>>
>> Ah. My mistake. I submit that this is also a bug in python's grammar.
>> There's probably some terribly good reason for it, though.
>
> How about 'conformance with standard mathematic notation', does this 
> count for a terribly good reason?

Yes. However, it's an excellent reason why python's precedence rules are 
wrong - in conventional mathematical notation, the unary minus, used to 
denote the sign of a literal number, does indeed have higher precedence 
than exponentiation: -1^2 evaluates to 1, not -1.

> What would one expect to be the result of 5^2 - 2^2, 29 or 21?

21.

> Would you expect 5^2 + - 2^2 to be different, even if you write it as 
> 5^2 + -2 ^ 2 ?

Yes: 5^2 + -2^2 is 29, however you write it.

> White space is not significant in math AFAIK ;-)

No, but there's a very big difference between unary and binary minus.

tom

-- 
When you mentioned INSERT-MIND-INPUT ... did they look at you like this?
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Tim Peters
[Steven D'Aprano]
...
> But this works:
> 
> py> inf = float("inf")
> py> inf
> inf

Another platform-dependent accident.  That does not work, for example,
on Windows.  In fact, the Microsoft C float<->string routines don't
support any way "to spell infinity" that works in the string->float
direction.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Steven D'Aprano
On Sun, 03 Jul 2005 15:46:35 +0100, Tom Anderson wrote:

> I think there would be a lot less confusion over the alleged inaccuracy of 
> floating point if everyone wrote in hex - indeed, i believe that C99 has 
> hex floating-point literals. C has always been such a forward-thinking 
> language!

No, all that would do is shift the complaint from "Python has a bug when
you divide 10 into 1.0" to "Python has a bug when you convert 0.1 into hex".

[snip]
>> But this works:
>>
>> py> inf = float("inf")
>> py> inf
>> inf
> 
> True. Still, i'd rather not have to rely on string parsing to generate a 
> fairly fundamental arithmetic quantity.

What happens when your Python script is running on a platform that can
deal with 1e300*1e300 giving 1e600 without overflow? Okay, maybe no such
platform exists today (or does it?), but it could exist, and your code
will fail on those systems.

I believe that the IEEE standard specifies that float("inf") should give
an infinity, just as float("0.0") should give a zero.

For production code, I'd wrap float("inf") in a try...except and only
fall back on your method if it raised an exception, and then I'd actually
test that your result was a real inf (eg by testing that inf+inf=inf).

[snip]

>>> The IEEE spec actually says that (x == nan) should be *false* for every x,
>>> including nan. I'm not sure if this is more or less stupid than what
>>> python does!
>>
>> Well, no, the IEEE standard is correct. NaNs aren't equal to anything, 
>> including themselves, since they aren't numbers.
> 
> I don't buy that. Just because something isn't a number doesn't mean it 
> can't be equal to something else, does it? I mean, we even say x == None 
> if x is indeed None.

Yes, but None does equal None, since there is only one None, and by
definition, a thing is equal to itself.

But NaNs are _not_ things. That is the whole point! Yes, we _represent_
INF-INF as a particular bit-pattern and call it NaN, but mathematically
subtracting infinity from infinity is not defined. There is no answer to
the question "what is infinity subtracted from infinity?".

We pretend that the answer is NaN, but that isn't right. The NaN is just
there as a placeholder for "there is no answer", so that we don't have
to sprinkle our code with a thousand and one tests.

Since INF-INF doesn't have an answer, we can't do this:

x = inf - inf
y = inf - inf

and expect that x == y. 


> Moreover, this freaky rule about NaNs means that this 
> is an exception to the otherwise absolutely inviolate law that x == x.

Yes. So what? Remove the NaN shorthand:

"The non-existent answer to this question is the same non-existent answer
to this other question."

It doesn't make sense to say that a non-thing is equal to anything -- even
to itself, since itself doesn't exist.

(Remember, a NaN is just an illusionary placeholder, not a number.)

> I'd rather have that simple, fundamental logical consistency than some IEEE 
> rocket scientist's practical-value-free idea of mathematical consistency.

Ah, from a _programmer's_ perspective, there is an argument that the
simplicity of just testing NaNs with equality outweighs the logical
silliness of doing such a thing. But, apart from testing whether a float
is a NaN, why would you ever want to do an equality test?

The only usage case I can think of is would be something like this:

def isNaN(x):
return x == SOME_KNOWN_NAN

But that won't work, because there are lots of different NaNs. 254 of
them, or twice that if you include signed NaNs (which you shouldn't, but
you do have to allow for them in equality testing).

Any good IEEE compliant system should already have a built-in function
that tests for NaNs.


[snip]

>>> And while i'm ranting, how come these expressions aren't the same:
>>>
>>> 1e300 * 1e300
>>> 1e300 ** 2
>>
>> Because this is floating point, not real maths :-)
>>
>> I get inf and Overflow respectively. What do you get?
> 
> The same. They really ought to give the same answer.

In real numbers, yes they should. In floating point, that is too much to
expect. In mathematics, the order you do your calculation shouldn't
matter. But in floating point, where there is rounding errors and finite
precision issues, it does.

The aim of the High Level Language designer is to insulate the programmer
from the ickiness of actual hardware implementation. Unfortunately, in the
case of floating point, you can't get away from the hardware limitations.


>>> And finally, does Guido know something about arithmetic that i don't,
>>> or is this expression:
>>>
>>> -1.0 ** 0.5
>>>
>>> Evaluated wrongly?
>>
>> No, it is evaluated according to the rules of precedence. It is
>> equivalent to -(1.0**0.5). You are confusing it with (-1.0)**0.5 which
>> fails as expected.
> 
> Ah. My mistake. I submit that this is also a bug in python's grammar.
> There's probably some terribly good reason for it, though.

Yes. You generally want exponentiation to have the highest precedence.

2*3**4 should give

Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Tim Peters
[Fredrik Johansson]
>>> I'd rather like to see a well implemented math.nthroot. 64**(1/3.0)
>>> gives 3.9996, and this error could be avoided.

[Steven D'Aprano]
>> >>> math.exp(math.log(64)/3.0)
>> 4.0
>>
>> Success!!!

[Tom Anderson]
> Eeenteresting. I have no idea why this works. Given that math.log is
> always going to be approximate for numbers which aren't rational powers of
> e (which, since e is transcendental, is all rational numbers, and
> therefore all python floats, isn't it?), i'd expect to get the same
> roundoff errors here as with exponentiation. Is it just that the errors
> are sufficiently smaller that it looks exact?

Writing exp(log(x)*y) rather than x**y is in _general_ a terrible
idea, but in the example it happens to avoid the most important
rounding error entirely:  1./3. is less than one-third, so 64**(1./3.)
is less than 64 to the one-third.  Dividing by 3 instead of
multiplying by 1./3. is where the advantage comes from here:

>>> 1./3.  # less than a third
0.1
>>> 64**(1./3.)  # also too small
3.9996
>>> exp(log(64)/3)  # happens to be on the nose
4.0

If we feed the same roundoff error into the exp+log method in
computing 1./3., we get a worse result than pow got:

>>> exp(log(64) * (1./3.))  # worse than pow's
3.9991

None of this generalizes usefully -- these are example-driven
curiousities.  For example, let's try 2000 exact cubes, and count how
often "the right" answer is delivered:

c1 = c2 = 0
for i in range(1, 2001):
p = i**3
r1 = p ** (1./3.)
r2 = exp(log(p)/3)
c1 += r1 == i
c2 += r2 == i
print c1, c2

On my box that prints

3 284

so "a wrong answer" is overwhelmingly more common either way.  Fredrik
is right that if you want a library routine that can guarantee to
compute exact n'th roots whenever possible, it needs to be written for
that purpose.

...

> YES! This is something that winds me up no end; as far as i can tell,
> there is no clean programmatic way to make an inf or a NaN;

All Python behavior in the presence of infinities, NaNs, and signed
zeroes is a platform-dependent accident, mostly inherited from that
all C89 behavior in the presence of infinities, NaNs, and signed
zeroes is a platform-dependent crapshoot.

> in code i write which cares about such things, i have to start:
>
> inf = 1e300 ** 1e300
> nan = inf - inf

That would be much more portable (== would do what you intended by
accident on many more platforms) if you used multiplication instead of
exponentiation in the first line.

...

> And then god forbid i should actually want to test if a number is NaN,
> since, bizarrely, (x == nan) is true for every x; instead, i have to
> write:
> 
> def isnan(x):
>return (x == 0.0) and (x == 1.0)

The result of that is a platform-dependent accident too.  Python 2.4
(but not eariler than that) works hard to deliver _exactly_ the same
accident as the platform C compiler delivers, and at least NaN
comparisons work "as intended" (by IEEE 754) in 2.4 under gcc and MSVC
7.1 (because those C implementations treat NaN comparisons as intended
by IEEE 754; note that MSVC 6.0 did not):

>>> inf = 1e300 * 1e300
>>> nan == nan
>>> nan = inf - inf
>>> nan == 1.0
False
>>> nan < 1.0
False
>>> nan > 1.0
False
>>> nan == nan
False
>>> nan < nan
False
>>> nan > nan
False
>>> nan != nan
True

So at the Python level you can do "x != x" to see whether x is a NaN
in 2.4+(assuming that works in the C with which Python was compiled;
it does under gcc and MSVC 7.1).

> The IEEE spec actually says that (x == nan) should be *false* for every x,
> including nan. I'm not sure if this is more or less stupid than what
> python does!

Python did nothing "on purpose" here before Python 2.4.

> And while i'm ranting, how come these expressions aren't the same:
>
> 1e300 * 1e300
> 1e300 ** 2

Because all Python behavior in the presence of infinities, NaNs and
signed zeroes is a platform-dependent accident.

> And finally, does Guido know something about arithmetic that i don't,

Probably yes, but that's not really what you meant to ask .

> or is this expression:
>
> -1.0 ** 0.5
>
> Evaluated wrongly?

Read the manual for the precedence rules.  -x**y groups as -(x**y). 
-1.0 is the correct answer.  If you intended (-x)**y, then you need to
insert parentheses to force that order.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread George Sakkis
"Tom Anderson" <[EMAIL PROTECTED]> wrote:

> >> And finally, does Guido know something about arithmetic that i don't, or
> >> is this expression:
> >>
> >> -1.0 ** 0.5
> >>
> >> Evaluated wrongly?
> >
> > No, it is evaluated according to the rules of precedence. It is
> > equivalent to -(1.0**0.5). You are confusing it with (-1.0)**0.5 which
> > fails as expected.
>
> Ah. My mistake. I submit that this is also a bug in python's grammar.
> There's probably some terribly good reason for it, though.

How about 'conformance with standard mathematic notation', does this
count for a terribly good reason ? What would one expect to be the
result of 5^2 - 2^2, 29 or 21 ? Would you expect 5^2 + - 2^2 to be
different, even if you write it as 5^2 + -2  ^ 2  ? White space is not
significant in math AFAIK ;-)

George

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread George Sakkis
"Steven D'Aprano" <[EMAIL PROTECTED]> wrote:

> Unfortunately, floating point maths is a bit of a black art. Try this
> simple calculation:
>
> py> 4.0/3 - 5.0/6
> 0.49989
>
> Should be 0.5 exactly.
>
> Many numbers which you can write exactly in decimal cannot be
> stored exactly in floating point. Even something as simple as one tenth
> 0.1 doesn't have an exact representation in binary:
>
> py> 1.0/10
> 0.10001

Given that 0.5 *can* be represented exactly in binary (try 0.3/0.6),
your first example illustrates something worse about floating point
arithmetic: not only many decimal numbers cannot be represented exactly
as binary floating point, but that the kind and the order of operations
in arithmetic expressions affects the accuracy of the result. *Even
worse* than that, errors can be accumulated over a sequence of
operations, so that even if each individual error is typically very
small, the overall error might be non-trivial. There's a whole area
studying the analysis and control of error in floating point arithmetic
so it's not quite black art for everyone; e.g. see
http://docs.sun.com/source/806-3568/ncg_goldberg.html,
http://http.cs.berkeley.edu/~demmel/cs267/lecture21/lecture21.html for
more.

George

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Tom Anderson
On Mon, 4 Jul 2005, Steven D'Aprano wrote:

> On Sun, 03 Jul 2005 10:56:42 +0100, Tom Anderson wrote:
>
>> On Sun, 3 Jul 2005, Steven D'Aprano wrote:
>>
>>> On Sun, 03 Jul 2005 02:22:23 +0200, Fredrik Johansson wrote:
>>>
 On 7/3/05, Tom Anderson <[EMAIL PROTECTED]> wrote:
> That's one way. I'd do:
>
> root = value ** 0.5
>
> Does that mean we can expect Guido to drop math.sqrt in py3k? :)

 I'd rather like to see a well implemented math.nthroot. 64**(1/3.0)
 gives 3.9996, and this error could be avoided.
>>>
>>> py> math.exp(math.log(64)/3.0)
>>> 4.0
>>>
>>> Success!!!
>>
>> Eeenteresting. I have no idea why this works. Given that math.log is
>> always going to be approximate for numbers which aren't rational powers of
>> e (which, since e is transcendental, is all rational numbers, and
>> therefore all python floats, isn't it?), i'd expect to get the same
>> roundoff errors here as with exponentiation. Is it just that the errors
>> are sufficiently smaller that it looks exact?
>
> I have no idea :-)
>
> Unfortunately, floating point maths is a bit of a black art. Try this
> simple calculation:
>
> py> 4.0/3 - 5.0/6
> 0.49989
>
> Should be 0.5 exactly.
>
> Many numbers which you can write exactly in decimal cannot be
> stored exactly in floating point. Even something as simple as one tenth
> 0.1 doesn't have an exact representation in binary:
>
> py> 1.0/10
> 0.10001

I realise that - but all that argues that your example shouldn't work 
either!

I think there would be a lot less confusion over the alleged inaccuracy of 
floating point if everyone wrote in hex - indeed, i believe that C99 has 
hex floating-point literals. C has always been such a forward-thinking 
language!

>>> Note how much simpler this would be if we could guarantee proper
>>> infinities and NaNs in the code. We could turn a 23-line block to a
>>> one-liner.
>>
>> YES! This is something that winds me up no end; as far as i can tell,
>> there is no clean programmatic way to make an inf or a NaN; in code i
>> write which cares about such things, i have to start:
>>
>> inf = 1e300 ** 1e300
>> nan = inf - inf
>>
>> Every bloody time. I'm going to be buggered if python ever rolls out some
>> sort of bigfloat support.
>
> It fails for me:
>
> py> inf = 1e300 ** 1e300
> Traceback (most recent call last):
>  File "", line 1, in ?
> OverflowError: (34, 'Numerical result out of range')

Oops. I meant to write "1e300 * 1e300" - multiplication, not 
exponentiation. My bad.

> But this works:
>
> py> inf = float("inf")
> py> inf
> inf

True. Still, i'd rather not have to rely on string parsing to generate a 
fairly fundamental arithmetic quantity.

>> And then god forbid i should actually want to test if a number is NaN,
>> since, bizarrely, (x == nan) is true for every x;
>
> Well dip me in chocolate and call me a Tim Tam, you're right. That is
> bizarre. No, that's not the word I want... that behaviour is broken.
>
>> instead, i have to
>> write:
>>
>> def isnan(x):
>>  return (x == 0.0) and (x == 1.0)
>>
>> The IEEE spec actually says that (x == nan) should be *false* for every x,
>> including nan. I'm not sure if this is more or less stupid than what
>> python does!
>
> Well, no, the IEEE standard is correct. NaNs aren't equal to anything, 
> including themselves, since they aren't numbers.

I don't buy that. Just because something isn't a number doesn't mean it 
can't be equal to something else, does it? I mean, we even say x == None 
if x is indeed None. Moreover, this freaky rule about NaNs means that this 
is an exception to the otherwise absolutely inviolate law that x == x. I'd 
rather have that simple, fundamental logical consistency than some IEEE 
rocket scientist's practical-value-free idea of mathematical consistency.

> Apple Computer had a maths library that implemented a superset of IEEE 
> arithmetic. It allowed for 254 different NaNs (twice that if you looked 
> at the sign bit, which you weren't supposed to do). This wasn't a 
> deliberate feature as such, it merely fell out naturally from the 
> bit-patterns that represented NaNs, but it was useful since Apple took 
> advantage of it by specifying certain particular NaNs for certain 
> failure modes. Eg NaN(1) might represent the square root of a negative 
> number, but NaN(2) might be INF-INF.
>
> Furthermore, you could easily query the class of a number (zero,
> normalised, denormalised, infinity, NaN), so you would test for a NaN by
> doing something like:
>
> if Kind(x) == NanKind: ...
>
> or
>
> if isNaN(x): ...

We should add that to python - although it would one one small step for 
NaN, one giant leap for NanKind.

Sorry.

>> And while i'm ranting, how come these expressions aren't the same:
>>
>> 1e300 * 1e300
>> 1e300 ** 2
>
> Because this is floating point, not real maths :-)
>
> I get inf and Overflow respectively. What do you get?

The same. They really ought to give the same answer.


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Steven D'Aprano
On Sun, 03 Jul 2005 10:56:42 +0100, Tom Anderson wrote:

> On Sun, 3 Jul 2005, Steven D'Aprano wrote:
> 
>> On Sun, 03 Jul 2005 02:22:23 +0200, Fredrik Johansson wrote:
>>
>>> On 7/3/05, Tom Anderson <[EMAIL PROTECTED]> wrote:
 That's one way. I'd do:

 root = value ** 0.5

 Does that mean we can expect Guido to drop math.sqrt in py3k? :)
>>>
>>> I'd rather like to see a well implemented math.nthroot. 64**(1/3.0)
>>> gives 3.9996, and this error could be avoided.
>>
>> py> math.exp(math.log(64)/3.0)
>> 4.0
>>
>> Success!!!
> 
> Eeenteresting. I have no idea why this works. Given that math.log is 
> always going to be approximate for numbers which aren't rational powers of 
> e (which, since e is transcendental, is all rational numbers, and 
> therefore all python floats, isn't it?), i'd expect to get the same 
> roundoff errors here as with exponentiation. Is it just that the errors 
> are sufficiently smaller that it looks exact?

I have no idea :-)

Unfortunately, floating point maths is a bit of a black art. Try this
simple calculation:

py> 4.0/3 - 5.0/6
0.49989

Should be 0.5 exactly.

Many numbers which you can write exactly in decimal cannot be
stored exactly in floating point. Even something as simple as one tenth
0.1 doesn't have an exact representation in binary:

py> 1.0/10
0.10001



>> Note how much simpler this would be if we could guarantee proper 
>> infinities and NaNs in the code. We could turn a 23-line block to a 
>> one-liner.
> 
> YES! This is something that winds me up no end; as far as i can tell, 
> there is no clean programmatic way to make an inf or a NaN; in code i 
> write which cares about such things, i have to start:
> 
> inf = 1e300 ** 1e300
> nan = inf - inf
> 
> Every bloody time. I'm going to be buggered if python ever rolls out some 
> sort of bigfloat support.

It fails for me:

py> inf = 1e300 ** 1e300
Traceback (most recent call last):
  File "", line 1, in ?
OverflowError: (34, 'Numerical result out of range')

But this works:

py> inf = float("inf")
py> inf
inf


> And then god forbid i should actually want to test if a number is NaN, 
> since, bizarrely, (x == nan) is true for every x; 

Well dip me in chocolate and call me a Tim Tam, you're right. That is
bizarre. No, that's not the word I want... that behaviour is broken.

> instead, i have to 
> write:
> 
> def isnan(x):
>   return (x == 0.0) and (x == 1.0)
> 
> The IEEE spec actually says that (x == nan) should be *false* for every x, 
> including nan. I'm not sure if this is more or less stupid than what 
> python does!

Well, no, the IEEE standard is correct. NaNs aren't equal to anything,
including themselves, since they aren't numbers.

Okay, infinity isn't a number either. But there are rules for arithmetic
for infinity, based on limit calculations, so it makes sense to treat
infinity as a number where possible.

Apple Computer had a maths library that implemented a superset of IEEE
arithmetic. It allowed for 254 different NaNs (twice that if you looked at
the sign bit, which you weren't supposed to do). This wasn't a
deliberate feature as such, it merely fell out naturally from the
bit-patterns that represented NaNs, but it was useful since Apple took
advantage of it by specifying certain particular NaNs for certain failure
modes. Eg NaN(1) might represent the square root of a negative number, but
NaN(2) might be INF-INF.

Furthermore, you could easily query the class of a number (zero,
normalised, denormalised, infinity, NaN), so you would test for a NaN by
doing something like: 

if Kind(x) == NanKind: ...

or

if isNaN(x): ...

> And while i'm ranting, how come these expressions aren't the same:
> 
> 1e300 * 1e300
> 1e300 ** 2

Because this is floating point, not real maths :-)

I get inf and Overflow respectively. What do you get?

> And finally, does Guido know something about arithmetic that i don't, or
> is this expression:
> 
> -1.0 ** 0.5
> 
> Evaluated wrongly?

No, it is evaluated according to the rules of precedence. It is equivalent
to -(1.0**0.5). You are confusing it with (-1.0)**0.5 which fails as
expected.


-- 
Steven.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: math.nroot [was Re: A brief question.]

2005-07-03 Thread Tom Anderson
On Sun, 3 Jul 2005, Steven D'Aprano wrote:

> On Sun, 03 Jul 2005 02:22:23 +0200, Fredrik Johansson wrote:
>
>> On 7/3/05, Tom Anderson <[EMAIL PROTECTED]> wrote:
>>> That's one way. I'd do:
>>>
>>> root = value ** 0.5
>>>
>>> Does that mean we can expect Guido to drop math.sqrt in py3k? :)
>>
>> I'd rather like to see a well implemented math.nthroot. 64**(1/3.0)
>> gives 3.9996, and this error could be avoided.
>
> py> math.exp(math.log(64)/3.0)
> 4.0
>
> Success!!!

Eeenteresting. I have no idea why this works. Given that math.log is 
always going to be approximate for numbers which aren't rational powers of 
e (which, since e is transcendental, is all rational numbers, and 
therefore all python floats, isn't it?), i'd expect to get the same 
roundoff errors here as with exponentiation. Is it just that the errors 
are sufficiently smaller that it looks exact?

> Note how much simpler this would be if we could guarantee proper 
> infinities and NaNs in the code. We could turn a 23-line block to a 
> one-liner.

YES! This is something that winds me up no end; as far as i can tell, 
there is no clean programmatic way to make an inf or a NaN; in code i 
write which cares about such things, i have to start:

inf = 1e300 ** 1e300
nan = inf - inf

Every bloody time. I'm going to be buggered if python ever rolls out some 
sort of bigfloat support.

And then god forbid i should actually want to test if a number is NaN, 
since, bizarrely, (x == nan) is true for every x; instead, i have to 
write:

def isnan(x):
return (x == 0.0) and (x == 1.0)

The IEEE spec actually says that (x == nan) should be *false* for every x, 
including nan. I'm not sure if this is more or less stupid than what 
python does!

And while i'm ranting, how come these expressions aren't the same:

1e300 * 1e300
1e300 ** 2

And finally, does Guido know something about arithmetic that i don't, or 
is this expression:

-1.0 ** 0.5

Evaluated wrongly?

tom

-- 
Please! Undo clips before opening handle.
-- 
http://mail.python.org/mailman/listinfo/python-list


math.nroot [was Re: A brief question.]

2005-07-02 Thread Steven D'Aprano
On Sun, 03 Jul 2005 02:22:23 +0200, Fredrik Johansson wrote:

> On 7/3/05, Tom Anderson <[EMAIL PROTECTED]> wrote:
>> That's one way. I'd do:
>> 
>> root = value ** 0.5
>> 
>> Does that mean we can expect Guido to drop math.sqrt in py3k? :)
> 
> I'd rather like to see a well implemented math.nthroot. 64**(1/3.0)
> gives 3.9996, and this error could be avoided.

py> 64**(1/3.0)
3.9996

Use the fact that if z = x**y, log(z) = y*log(x).

py> import math
py> math.exp(1/3.0*math.log(64))
3.9991

That's even less accurate.

py> math.exp(math.log(64)/3.0)
4.0

Success!!!

Another (random-ish) example:

py> 17**5
1419857
py> 1419857**(1.0/5)
17.004
py> math.exp(math.log(1419857)/5.0)
17.0


def nroot(x, y):
"""Returns the yth root of x. 

More accurate than using x**(1/y).
Handles most, but not all, edge cases correctly. (Does not check for
y as either negative zero or negative infinity.) 
"""
if x < 0.0:
raise ValueError("Complex valued result.")
if y == 0.0:  # x**inf
if x > 1.0:
try:
return float("inf")
except:
try:
return 1.0/0.0
except:
raise ValueError("Overflow")
elif x == 1.0:  # 1**N = 1 for any positive N
return 1.0
else:  # 0**N = 0 for any non-zero N
return 0.0

# check the limiting case where y is positive infinity
if 1.0/y == 0.0:
# x**0 = 1 for all real x (including the limiting case x = 0)
return 1.0

if x == 0.0:  # 0**N = 0 for any non-zero N
return 0.0
else:
return math.exp(math.log(x)/y)


Note how much simpler this would be if we could guarantee proper
infinities and NaNs in the code. We could turn a  23-line block to a
one-liner.


-- 
Steven.

-- 
http://mail.python.org/mailman/listinfo/python-list