Opened 6 years ago

Last modified 22 months ago

#15344 new defect

asin(2.0) should not return NaN

Reported by: davidamadore Owned by:
Priority: major Milestone: sage-6.4
Component: symbolics Keywords: functions
Cc: Merged in:
Authors: Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Description

Currently, asin(2.0) returns NaN, whereas asin(CC(2.0)) returns the more expected value of 1.57079632679490 - 1.31695789692482*I (that's π/2 − acosh(2)·I).

I can understand the logic of not wanting to return a complex value for a real argument, but since sqrt(-1.0) already returns 1.0*I, there are already parts of Sage which break that logic.

Conversely, this convention of returning NaN causes many difficulties when plotting functions. For example, plot(imag(asin(x)),(x,0,3)) does not at all return what is expected. And, of course, plot(imag(asin(CC(x))),(x,0,3)) does not work, so one has to write plot(lambda t: imag(asin(CC(t))),(0,3)), which, in this simple example, might be a very minor inconvenience, but can become a great annoyance when dealing with more complicated situations.

The fact that Sage sometimes considers values as reals even though they were obtained by complex computations adds insult to injury:

sage: N(asin((1+I)*(1-I)))
NaN
sage: asin((1.+1.*I)*(1.-1.*I))
1.57079632679490 - 1.31695789692482*I

(if asin(2) persists in returning NaN, then at least (1+I)*(1-I) should refrain from looking too much like an integer until it is explicitly coerced as such).

Change History (15)

comment:1 Changed 6 years ago by vbraun_spam

  • Milestone changed from sage-6.1 to sage-6.2

comment:2 Changed 6 years ago by vbraun_spam

  • Milestone changed from sage-6.2 to sage-6.3

comment:3 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.3 to sage-6.4

comment:4 Changed 3 years ago by rws

  • Component changed from numerical to symbolics
  • Summary changed from asin(2.0) shound not return NaN to asin(2.0) should not return NaN

comment:5 follow-up: Changed 3 years ago by rws

This touches several issues. Maybe we should agree for now to get different results with a float and a complex/CC type. The same difference exists with real/complex ball arguments. It's not good that there is no easy way to specify argument type when plotting, a better workaround however IMHO is to add epsilon*I, e.g. plot(imag(asin(x+I*1e-10)),(x,0,3)). This should be addressed (complex() symbolic function?) but not here.

There are already other parts where complex is returned on float input, right. However changing the output of asin(2.0) and asin(RBF(2.0)) would mean changing the interface to the mpfr and arb packages that are used here. This is possible.

Now (1+I)*(1-I) and (1.+1.*I)*(1.-1.*I) are completely differently handled than the above because they are symbolic expressions. There were recent changes in Pynac that made asin((1.+1.*I)*(1.-1.*I)) return NaN as well. Adapting this to the above numeric changes would be easy. I think asin(2) should then also return 1/2*pi - I*arccosh(2) instead of arcsin(2).

comment:6 in reply to: ↑ 5 ; follow-up: Changed 2 years ago by vdelecroix

Replying to rws:

Maybe we should agree for now to get different results with a float and a complex/CC type. The same difference exists with real/complex ball arguments.

Indeed, asin: RR -> RR (inverse of sin) is different from asin: CC -> CC (a principal value). In the same veine, the real logarithm is not defined for negative inputs

sage: import math, cmath
sage: math.log(-1r)
Traceback (most recent call last):
...
ValueError: math domain error
sage: cmath.log(-1r)
3.141592653589793j

To my mind, Sage is doing wrong here

sage: RR(-1).log()
3.14159265358979*I
sage: RDF(-1).log()
3.141592653589793*I

It's not good that there is no easy way to specify argument type when plotting, [...]

I do not think that this is the real problem. As explained before, acosh, log, etc mean different things (with various domains and ranges). This information should be known by the function (aka it should be a polymorphic function). It should also be possible to bind a well defined mathematical function from the polymorphic one such as

sage: log.bind(domain=RR, range=RR)
The real logarithm on Real Field with 53 bits of precision
sage: log.bind(domain=CC, range=CC)
The principal value of logarithm on Complex Field with 53 bits of precision

The above binded functions should know about there domain, range, singularities, etc.

comment:7 in reply to: ↑ 6 ; follow-ups: Changed 2 years ago by rws

Replying to vdelecroix:

The above binded functions should know about there domain, range, singularities, etc.

All nice but before even thinking about that this should be fixed:

sage: from sage.sets.set import is_Set
sage: is_Set(RR)
False
sage: is_Set(RealSet(-oo,oo))
False

Or provide custom formal sets representing the reals/complexes.

comment:8 in reply to: ↑ 7 Changed 2 years ago by rws

Replying to rws:

sage: from sage.sets.set import is_Set
sage: is_Set(RealSet(-oo,oo))
True

Oh my I totally forgot that I already implemented that as part of #24171. I'll extract it and make a separate ticket right now.

comment:9 Changed 2 years ago by rws

Please review #24443.

comment:10 in reply to: ↑ 7 ; follow-up: Changed 2 years ago by vdelecroix

Replying to rws:

Replying to vdelecroix:

The above binded functions should know about there domain, range, singularities, etc.

All nice but before even thinking about that this should be fixed:

sage: from sage.sets.set import is_Set
sage: is_Set(RR)
False
sage: is_Set(RealSet(-oo,oo))
False

Or provide custom formal sets representing the reals/complexes.

You did a double mistake here. In Sage RR is not the set of real numbers but of floating point numbers with mantissa on 53 bits.

sage: RR
Real Field with 53 bits of precision

Next, is_Set checks whether the type of RR inherits from Set which is not what you want to check here. You should rather rely on categories

sage: RR in Sets()
True

comment:11 in reply to: ↑ 10 ; follow-up: Changed 2 years ago by rws

Replying to vdelecroix:

You did a double mistake here. In Sage RR is not the set of real numbers but of floating point numbers with mantissa on 53 bits.

What good does it to have that domain on a symbolic function versus having a formal real set domain? Having a domain affects not only FP evaluation but also normal immediate evaluation of symbolic argument, and only a formal domain has useful implications.

Next, is_Set checks whether the type of RR inherits from Set which is not what you want to check here. You should rather rely on categories

That shows that the documentation of is_Set is incomplete.

comment:12 Changed 2 years ago by vdelecroix

I don't even see the point of having is_Set in the global namespace...

comment:13 in reply to: ↑ 11 ; follow-up: Changed 2 years ago by vdelecroix

Replying to rws:

Replying to vdelecroix:

You did a double mistake here. In Sage RR is not the set of real numbers but of floating point numbers with mantissa on 53 bits.

What good does it to have that domain on a symbolic function versus having a formal real set domain? Having a domain affects not only FP evaluation but also normal immediate evaluation of symbolic argument, and only a formal domain has useful implications.

It is good because a formal real set has a lot of concrete implementations RealField(prec), RealBallField(prec), RealIntervalField(prec) and possibly in the future some more symbolic ones.

comment:14 in reply to: ↑ 13 Changed 2 years ago by rws

Replying to vdelecroix:

Replying to rws:

Replying to vdelecroix:

You did a double mistake here. In Sage RR is not the set of real numbers but of floating point numbers with mantissa on 53 bits.

What good does it to have that domain on a symbolic function versus having a formal real set domain? Having a domain affects not only FP evaluation but also normal immediate evaluation of symbolic argument, and only a formal domain has useful implications.

It is good because a formal real set has a lot of concrete implementations RealField(prec), RealBallField(prec), RealIntervalField(prec) and possibly in the future some more symbolic ones.

I don't mind other symbolic domains that are subsets of the formal reals---again, what good is it to have a purely floating-point domain like RealField(53) on a symbolic function?

comment:15 Changed 22 months ago by rws

asin(2.0) would be fixed in #24428.

Note: See TracTickets for help on using tickets.