ceylon / ceylon.language

DEPRECATED
Apache License 2.0
153 stars 57 forks source link

1.0^infinity #737

Closed gavinking closed 9 years ago

gavinking commented 9 years ago

Wikipedia claims that the IEEE standard mandates that pow(1.0, ∞) evaluates to 1.0, along with pow(0.0, 0.0) and pow(∞, 0.0), and that seems intuitively correct to me. I can see how pow(-1.0, ∞) should be NaN, but that seems a pretty different case.

However, Java's Math.pow() function apparently has its own idea and Math.pow(1.0, Math.POSITIVE_INFINITY) evaluates to NaN, and if I', reading the ECMA spec right, it seems to specify the same thing.

What should Ceylon do here?

Does anyone happen to have a copy of the IEEE spec?

Note also this comment in the Dart issue tracker.

lucaswerkmeister commented 9 years ago

Does anyone happen to have a copy of the IEEE spec?

I can get access via my university account. Does Wikipedia refer to a specific section?

lucaswerkmeister commented 9 years ago

Found it. 9.2.1 Special values, pp. 43–45.

For the pow function […] pow(x, ±0) is 1 for any x (even a zero, quiet NaN, or infinity) […] pow(+1,y) is 1 for any y (even a quiet NaN)

lucaswerkmeister commented 9 years ago

Note, however, that the standard also defines pown and powr. The descriptions are:

[…] the pown function (integral exponents only) […] […] the pow function (integral exponents get special treatment) […] […] the powr function (derived by considering only exp(y×log(x))) […]

lucaswerkmeister commented 9 years ago

And:

powr(±0, ±0) signals the invalid operation exception powr(+∞, ±0) signals the invalid operation exception powr(+1, ±∞) signals the invalid operation exception

lucaswerkmeister commented 9 years ago

So perhaps Java’s and ECMAScript’s pow is based on IEEE’s powr, replacing “invalid operation exception” with NaN.

jvasileff commented 9 years ago

It looks like the IEEE spec for this was released in 2008 (after java.lang.Math) - https://en.wikipedia.org/wiki/IEEE_754_revision. Of course, that doesn't tell us what they would have done.

lucaswerkmeister commented 9 years ago

That’s true… the original IEEE 754-1985 doesn’t define any operations beside

An implementation shall provide the add, subtract, multiply, divide, and remainder operation

and

The square root operation shall be provided.

gavinking commented 9 years ago

No, Java's pow() isn't powr() either. Look at powr(0,0) and powr(infinity,0).

jvasileff commented 9 years ago

I think I'd go with IEEE, primarily because it seems like the least opinionated approach. But also, the rules look reasonable enough.

I thought pow(-1.0, ±∞) == 1 was strange at first, but with floats, you've already "lost" once y is a large number, all of which are all even.

Edit: changed Dart API url; the old one stopped working

lucaswerkmeister commented 9 years ago

This is a mess. Examined languages:

Examined special cases:

My results:

I think we should follow C, Dart, Go, Python.

gavinking commented 9 years ago

@jvasileff well it does seem to me wrong that pow(-1.0, ∞) == 1.0. I don't see where that comes from. pow(-1.0, n) does not converge as n approaches .

So I don't see where IEEE gets that from.

jvasileff commented 9 years ago

@gavinking but we're taking about floats, where really big numbers at some point just become "infinity" (instead of triggering an overflow exception). And for big numbers, the answer is 1.0, since in this fake-number-world, all big numbers are even.

So I think the interpretation is that infinity just means a number outside of the representable range (which surely must be an even integer!), and not a proper infinity in a mathematical sense.

Bottom line: folks shouldn't be doing this sort of calculation with floats, but to stop them entirely, we'd have to have pow(-1.0, *) be undefined.

gavinking commented 9 years ago

@jvasileff That's not true. Really big negative numbers become -infinity, not infinity.

jvasileff commented 9 years ago

Sure, I was speaking in terms of magnitude.

gavinking commented 9 years ago

Oh, sorry, I misunderstood your argument. Yeah, OK, so with limited precision, all large floating point exponents are even. That's ... a very weird side-effect of limited-precision floating-point arithmetic.

FroMage commented 9 years ago

@gavinking: where's that Wikipedia page you talk about, I can't find it?

I can implement that for both JS and JVM, but I'd like to see some better specs, since it's pretty famous math is a foreign language to me.

For the pow function […] pow(x, ±0) is 1 for any x (even a zero, quiet NaN, or infinity) […] pow(+1,y) is 1 for any even y (even a quiet NaN)

@lucaswerkmeister this says infinity but does not say positive/negative. Am I to conclude that it's for both infinities?

I thought pow(-1.0, ±∞) == 1 was strange at first, but with floats, you've already "lost" once y is a large number, all of which are all even.

@jvasileff where did you find that? I can't find it in @gavinking's issue description, nor in the quoted IEEE spec in comments. Should I implement that too?

lucaswerkmeister commented 9 years ago

@FroMage pretty sure, yes, especially since it’s only a clarification for “any x”.

FroMage commented 9 years ago

OK fine.

jvasileff commented 9 years ago

@FroMage in the Dart and Go links here https://github.com/ceylon/ceylon.language/issues/737#issuecomment-136228316 which claim to be consistent with IEEE Standard 754-2008.

FroMage commented 9 years ago

@jvasileff: Dart says:

pow(+1, y) is 1 for any y (even a quiet NaN)

But @lucaswerkmeister quoted IEEE as saying:

pow(+1,y) is 1 for any even y (even a quiet NaN)

Not sure what to make of that.

lucaswerkmeister commented 9 years ago

hang on, I might’ve misquoted

FroMage commented 9 years ago

aha :)

lucaswerkmeister commented 9 years ago

yup, sorry.

pow (+1, y ) is 1 for any y (even a quiet NaN)

lucaswerkmeister commented 9 years ago

and that’s why I don’t copy+paste out of that stupid document :D

lucaswerkmeister commented 9 years ago

fixed in my comment above

FroMage commented 9 years ago

OK thanks.

lucaswerkmeister commented 9 years ago

Lemme give y’all folks the spec so we can discuss on the same level :)

pow

FroMage commented 9 years ago

I've updated the JS and JVM runtime to align us with what I believe is the IEEE spec. Please review. If you wish to deviate from the IEEE spec, at least now you can see where in the code it has to be done ;)

I won't close this until you guys come to an agreement, but I vote for following the IEEE spec.

lucaswerkmeister commented 9 years ago

@FroMage what’s pow(1.5, +∞) now?

lucaswerkmeister commented 9 years ago

oh I see, that’s a test case. good

gavinking commented 9 years ago

The consensus seems to be to go with the IEEE definition of pow(). Fine by me. I'll assume @FroMage's impl is good and close this issue.