Opened 11 years ago

Closed 11 years ago

# python ints vs sage ints with respect to powers weirdness

Reported by: Owned by: dimpase AlexGhitza major sage-4.7.2 coercion rkirov, SimonKing sage-4.7.2.alpha3 Dmitrii Pasechnik William Stein N/A

```print type(int(3) + 3)
print type(int(3) * 3)
print type(3 ^ int(3))
print type(int(3) ^ 3)
```

first three are Sage Integers but last one is just a Python int. Worse still:

```sage: int(3)^-3
0.037037037037037035
sage: type(int(3)^-3)
<type 'float'>
sage: int(3)^QQ(-3)
1/27
sage: type(int(3)^QQ(-3))
<type 'sage.rings.rational.Rational'>
```

is very inconsistent, as well as leads to loss of precision, even though it can be avoided. As well as

```sage: p(x)=x^-3
sage: p(int(3))
1/27
```

is not consistent.

Apply trac_11779.patch to the Sage library.

### comment:2 Changed 11 years ago by dimpase

• Status changed from new to needs_review

### comment:3 follow-up: ↓ 4 Changed 11 years ago by leif

So what do you expect the result types to be?

IMHO the fact that `3r^3` yields a Python `int` is pretty correct; with negative exponents the interpretation is less straightforward.

I'd interpret `int(x)^(-any)` as `(int(1)/int(x))^(any)`, so the result should be `float` if `any` is positive.

### comment:4 in reply to: ↑ 3 ; follow-up: ↓ 5 Changed 11 years ago by dimpase

So what do you expect the result types to be?

IMHO the fact that `3r^3` yields a Python `int` is pretty correct; with negative exponents the interpretation is less straightforward.

in all other operations (see the ticket description), the Sage type takes the precedence over Python. I certainly don't mind `int(3)^int(3)` being int though. in fact, with the patch applied, the behaviour is as follows:

```sage: type(int(3)^3)
<type 'sage.rings.integer.Integer'>
sage: type(int(3)^int(3))
<type 'int'>
sage: type(int(3)^int(-3))
<type 'float'>
sage: type(int(3)^-3)
<type 'sage.rings.rational.Rational'>
```

this is the behaviour that is much less confusing.

### comment:5 in reply to: ↑ 4 ; follow-up: ↓ 6 Changed 11 years ago by leif

• Component changed from basic arithmetic to coercion

So what do you expect the result types to be?

IMHO the fact that `3r^3` yields a Python `int` is pretty correct; with negative exponents the interpretation is less straightforward.

in all other operations (see the ticket description), the Sage type takes the precedence over Python.

Exponentiation is different, i.e., the type of the exponent doesn't matter at all, only its value.

I certainly don't mind `int(3)^int(3)` being int though.

Why should one?

in fact, with the patch applied, the behaviour is as follows:

```...
sage: type(int(3)^3)
<type 'sage.rings.integer.Integer'>
...
```

which is simply wrong, because `3r^3` is `3r * 3r * 3r`, so the type of the result should be the base's type (unless the result is not an integer, in which case Python's rules should apply, leading to a `float` result.)

The following is equally wrong for the same reason. (This is a bug.)

```sage: type(int(3)^-3)
<type 'sage.rings.rational.Rational'>
```

this is the behaviour that is much less confusing.

Less confusing to whom? Honestly, every school child should know the difference.

Ok, one could argue that `3r * 3` could be interpreted as `3r + 3r + 3r` as well (leading to result type `int` rather than `Integer`), but this would break commutativity.

Worth a discussion on sage-devel... (quite curious of the opinions :P )

### comment:6 in reply to: ↑ 5 ; follow-up: ↓ 8 Changed 11 years ago by leif

• Authors set to Dmitrii Pasechnik

[...]

(This is a bug.)

```sage: type(int(3)^-3)
<type 'sage.rings.rational.Rational'>
```

I meant `type(int(3)^QQ(-3))` not being `float` is a bug (currently in Sage).

We furthermore currently have:

```sage: type(int(3)^QQ(-3))
<type 'sage.rings.rational.Rational'>
sage: type(int(3)^ZZ(-3))
<type 'float'>
```

which is obviously inconsistent, where IMHO the latter is correct, but not the former.

(Nevertheless, I know mathematicians tend to care less about types... ;-) )

### comment:7 Changed 11 years ago by leif

Also

```sage: type(int(3)^RR(-3))
<type 'sage.rings.real_mpfr.RealNumber'>
```

is wrong.

Worse:

```sage: type(int(3)^RR(3))
<type 'sage.rings.real_mpfr.RealNumber'>
```

Much worse:

```sage: type(int(3)^CC(3))
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)

/tmp/Sage/sage-4.7.2.alpha2/devel/sage-11778/<ipython console> in <module>()

/tmp/Sage/sage-4.7.2.alpha2/local/lib/python2.6/site-packages/sage/rings/complex_number.so in sage.rings.complex_number.ComplexNumber.__pow__ (sage/rings/complex_number.c:6289)()

AttributeError: 'int' object has no attribute 'log'
```

### comment:8 in reply to: ↑ 6 Changed 11 years ago by SimonKing

(Nevertheless, I know mathematicians tend to care less about types... ;-) )

Actually, I'd guess that mathematicians tend to prefer Sage Integer over Python int, since they are sceptical about int overflow...

### comment:9 Changed 11 years ago by dimpase

• Description modified (diff)

### comment:10 Changed 11 years ago by dimpase

• Description modified (diff)

### comment:11 Changed 11 years ago by dimpase

• Description modified (diff)

### comment:12 Changed 11 years ago by dimpase

• Description modified (diff)

### comment:13 Changed 11 years ago by klee

I agree with leif. I think any in "int(3)any" should be converted to an integer n (or -n), and then int(3)any equals int(3) multiplied n times with itself (or numerical inverse of int(3) multiplied n times with itself). Thus int(3)any is of type float always. If any cannot be converted to an integer, then an exception should be raised.

Thus int(3)3, int(3)QQ(3), int(3)ZZ(3), int(3)CC(3) all results in Pythonic integer 27. int(3)-3, int(3)QQ(-3), int(3)ZZ(-3), int(3)CC(-3) all results in Pythonic float 0.037037037037037028.

By the way, I think there is nothing wrong with this

```sage: p(x)=x^-3
sage: p(int(3))
1/27
```

because int(3) is converted to a Sage expression first. See

```sage: q(x)=x
sage: type(q(int(3)))
<type 'sage.symbolic.expression.Expression'>
```

So I think this ticket and the patch is misdirected.

### comment:14 follow-up: ↓ 15 Changed 11 years ago by klee

(Sorry for badly formated comment) I agree with leif. I think any in `int(3)^any` should be converted to an integer n (or -n), and then `int(3)^any` equals `int(3)` multiplied n times with itself (or numerical inverse of `int(3)` multiplied n times with itself). Thus `int(3)^any` is of type float always. If any cannot be converted to an integer, then an exception should be raised.

Thus `int(3)^3`, `int(3)^QQ(3)`, `int(3)^ZZ(3)`, `int(3)^CC(3)` all result in Pythonic integer `27`, and `int(3)^-3`, `int(3)^QQ(-3)`, `int(3)^ZZ(-3)`, `int(3)^CC(-3)` all result in Pythonic float `0.037037037037037028`.

By the way, I think there is nothing wrong with this

```sage: p(x)=x^-3
sage: p(int(3))
1/27
```

because `int(3)` is converted to a Sage expression first. See

```sage: q(x)=x
sage: type(q(int(3)))
<type 'sage.symbolic.expression.Expression'>
```

So I think this ticket and the patch is misdirected.

### comment:15 in reply to: ↑ 14 ; follow-up: ↓ 16 Changed 11 years ago by dimpase

(Sorry for badly formated comment) I agree with leif. I think any in `int(3)^any` should be converted to an integer n (or -n), and then `int(3)^any` equals `int(3)` multiplied n times with itself (or numerical inverse of `int(3)` multiplied n times with itself).

What do you mean by "numerical inverse", and why you think this is the right precedence for operations? Leif here gives arguments based on algebraic properties, so it should be, for algebraic consistency that he cares about so much, that `int(3)^-3==int(1)/int(3)^3`, but this is not the case now, as Python 2 will convert 1/27 to 0.

I advocate the rule that a binary operation involving a Sage integer and a Python int should always produce a Sage type, as this is the case with all the other binary operations. Do you like this?

To me, your and Leif's arguments read as "I prefer the status quo to making Sage a more consistent system".

### comment:16 in reply to: ↑ 15 ; follow-up: ↓ 17 Changed 11 years ago by leif

Leif here gives arguments based on algebraic properties, so it should be, for algebraic consistency that he cares about so much, that `int(3)^-3==int(1)/int(3)^3`, but this is not the case now, as Python 2 will convert 1/27 to 0.

What makes you think I meant Python's broken `/` operator on `int`s? As I said on sage-devel, the behaviour of that operator on `int`s is useless since there's explicit truncating integer division already, namely `//`.

I advocate the rule that a binary operation involving a Sage integer and a Python int should always produce a Sage type, as this is the case with all the other binary operations.

The notion of "binary operations" has no meaning in this context, as the desired behaviour w.r.t. result types should depend on the definition of the function, especially its commonly used signature, not its arity.

For exponentiation, the type of the exponent is irrelevant, only its value matters to deduce the type of the result of the operation, just like for shift operations (which of course aren't commutative either).

Or would you say `type( value << shift )` should depend on the type of `shift`?

This might perhaps look "consistent" from a syntactical point of view, but simply isn't sound, i.e. doesn't make any sense in the semantic domain.

To me, your and Leif's arguments read as "I prefer the status quo to making Sage a more consistent system".

Definitely not, since there are a lot of inconsistencies already which should IMHO be fixed, but not in the way you propose.

### comment:17 in reply to: ↑ 16 ; follow-up: ↓ 18 Changed 11 years ago by dimpase

Leif here gives arguments based on algebraic properties, so it should be, for algebraic consistency that he cares about so much, that `int(3)^-3==int(1)/int(3)^3`, but this is not the case now, as Python 2 will convert 1/27 to 0.

What makes you think I meant Python's broken `/` operator on `int`s? As I said on sage-devel, the behaviour of that operator on `int`s is useless since there's explicit truncating integer division already, namely `//`.

I advocate the rule that a binary operation involving a Sage integer and a Python int should always produce a Sage type, as this is the case with all the other binary operations.

The notion of "binary operations" has no meaning in this context, as the desired behaviour w.r.t. result types should depend on the definition of the function, especially its commonly used signature, not its arity.

well, being an algebraist by training and active in this research area for over 20 years, I tend to think that I know how to distinguish a binary operation from something else. And in my (not so in this case) humble opinion I think that exponentiation is a binary operation in this case.

For exponentiation, the type of the exponent is irrelevant, only its value matters to deduce the type of the result of the operation, just like for shift operations (which of course aren't commutative either).

Or would you say `type( value << shift )` should depend on the type of `shift`?

it can, potentially; e.g. when shifting is not understood in a narrow context of binary words.

This might perhaps look "consistent" from a syntactical point of view, but simply isn't sound, i.e. doesn't make any sense in the semantic domain.

Look, I know an opinion on this issue of a lot of unhappy beginning users of Sage (the undergrads I currently teach), and they are dazed and confused by this inconsistency, among others. And I am merely trying to make Sage easier to use for them on this ticket.

### comment:18 in reply to: ↑ 17 ; follow-up: ↓ 19 Changed 11 years ago by klee

well, being an algebraist by training and active in this research area for over 20 years, I tend to think that I know how to distinguish a binary operation from something else. And in my (not so in this case) humble opinion I think that exponentiation is a binary operation in this case.

Then you know that multiplication is a basic binary operation of a ring, but exponentiation is simply a notation involving two values, one from the ring, the other from integers.

Look, I know an opinion on this issue of a lot of unhappy beginning users of Sage (the undergrads I currently teach), and they are dazed and confused by this inconsistency, among others. And I am merely trying to make Sage easier to use for them on this ticket.

The right direction for beginners is to let them know the difference between `int(3)` and `3` (Sage Integer) and that `3` behaves more mathematically than `int(3)` which suffers from numerical treatment.

### comment:19 in reply to: ↑ 18 Changed 11 years ago by dimpase

well, being an algebraist by training and active in this research area for over 20 years, I tend to think that I know how to distinguish a binary operation from something else. And in my (not so in this case) humble opinion I think that exponentiation is a binary operation in this case.

Then you know that multiplication is a basic binary operation of a ring, but exponentiation is simply a notation involving two values, one from the ring, the other from integers.

Ever heard about `exp()`? Exponentiation is a jolly good binary operation on positive real numbers.

Look, I know an opinion on this issue of a lot of unhappy beginning users of Sage (the undergrads I currently teach), and they are dazed and confused by this inconsistency, among others. And I am merely trying to make Sage easier to use for them on this ticket.

The right direction for beginners is to let them know the difference between `int(3)` and `3` (Sage Integer) and that `3` behaves more mathematically than `int(3)` which suffers from numerical treatment.

Try to convince a beginner that the inconsistencies that got this ticket started are OK, without saying that Sage has not made a good choice.

### comment:20 follow-up: ↓ 21 Changed 11 years ago by was

• Status changed from needs_review to needs_work

Can you also add a doctest that illustrates this:

```   sage: type(int(3)^2)
...Integer...
```

I'm in favor of this change. It was always planned to add `__pow__` to the coercion model, and have Sage types be favored over Python types (just as the are for the other arithmetic operations), but nobody got around to it. This patch doesn't make such a big sweeping change as adding `__pow__` to the coercion model, but it is a step in the right direction.

### Changed 11 years ago by dimpase

slightly more optimized version

### comment:21 in reply to: ↑ 20 Changed 11 years ago by dimpase

• Status changed from needs_work to needs_review

Can you also add a doctest that illustrates this:

```    sage: type(int(3)^2)
...Integer...
```

Done. I have also added `type(int(3)^int(3))` doctest to show how to stick with 'int', if needed.

### comment:22 Changed 11 years ago by was

• Status changed from needs_review to positive_review

Looks good to me.

### comment:23 Changed 11 years ago by leif

• Description modified (diff)
• Reviewers set to William Stein

Please don't put links to the HTML version of a patch into the description.

Trac wiki mark-up is `[attachment:here_comes_the_filename]`.

Wonder whether your undergrads will complain that `[1r][0]` (or `(1r,)[0]`) doesn't yield a Sage `Integer`...

### comment:24 Changed 11 years ago by leif

• Merged in set to sage-4.7.2.alpha3
• Resolution set to fixed
• Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.