Repository: sympy/sympy

Issue:
make Add._eval_power handle Float coefficients better
I'm not sure if this has been reported before because I'm not exactly sure how to describe it. But I find that sympy is generating some expressions which have some constant factors rather strangely factored out in places, such as this:

```
-0.647*x -2.15e-16*sqrt(-5.669e+29*x**4 - 2.961e+30*x**3 -4.999e+30*x**2 -2.961e+30*x-5.669e+29)
```

This particular output was created by calling solve(eq, y) on an equation that was quadratic in y and quartic in x. The code below will generate the output above.

```
eq = 0.0121787141081027*x**4 + 0.0636077296587915*x**3 + 0.302270434899319*x**2 + 0.15709634216953*x + 0.465497194955889*y**2 + y*(0.60235044978107*x + 0.144496237696458) + 0.0233920806625508

expr = solve(eq,y)

expr[1]
```

The coefficients in the input equation were all fairly close to 1, so I don't understand why sympy decided to pull 2e-16 out of the square root while at the same time multiplying everything under the radical sign by 4e+32. More importantly, I can't find any simplification commands that will convince sympy to factor those coefficients back in. In addition to making the equation needlessly long and messy, it can introduce loss of precision when numerically evaluating the output.

Any suggestions?


Discussion:

Patch:
diff --git a/sympy/core/add.py b/sympy/core/add.py
index 2979af20cb..34b0f3b136 100644
--- a/sympy/core/add.py
+++ b/sympy/core/add.py
@@ -388,6 +388,20 @@ def _eval_power(self, e):
                     return _unevaluated_Mul(
                         r - i*S.ImaginaryUnit,
                         1/(r**2 + i**2))
+        elif e.is_Number and abs(e) != 1:
+            # handle the Float case: (2.0 + 4*x)**e -> 2.**e*(1 + 2.0*x)**e
+            c, m = zip(*[i.as_coeff_Mul() for i in self.args])
+            big = 0
+            float = False
+            for i in c:
+                float = float or i.is_Float
+                if abs(i) > big:
+                    big = 1.0*abs(i)
+                    s = -1 if i < 0 else 1
+            if float and big and big != 1:
+                addpow = Add(*[(s if abs(c[i]) == big else c[i]/big)*m[i]
+                             for i in range(len(c))])**e
+                return big**e*addpow
 
     @cacheit
     def _eval_derivative(self, s):


Test patch:
diff --git a/sympy/core/tests/test_power.py b/sympy/core/tests/test_power.py
index 8188a81aaf..aca6ddd156 100644
--- a/sympy/core/tests/test_power.py
+++ b/sympy/core/tests/test_power.py
@@ -452,3 +452,19 @@ def test_better_sqrt():
     assert sqrt(-I/2) == Mul(S.Half, 1 - I, evaluate=False)
     # fractional im part
     assert Pow(-9*I/2, 3/S(2)) == 27*(1 - I)**3/8
+
+
+def test_issue_2993():
+    x = Symbol('x')
+    assert str((2.3*x - 4)**0.3) == '1.5157165665104*(0.575*x - 1)**0.3'
+    assert str((2.3*x + 4)**0.3) == '1.5157165665104*(0.575*x + 1)**0.3'
+    assert str((-2.3*x + 4)**0.3) == '1.5157165665104*(1 - 0.575*x)**0.3'
+    assert str((-2.3*x - 4)**0.3) == '1.5157165665104*(-0.575*x - 1)**0.3'
+    assert str((2.3*x - 2)**0.3) == '1.28386201800527*(x - 0.869565217391304)**0.3'
+    assert str((-2.3*x - 2)**0.3) == '1.28386201800527*(-x - 0.869565217391304)**0.3'
+    assert str((-2.3*x + 2)**0.3) == '1.28386201800527*(0.869565217391304 - x)**0.3'
+    assert str((2.3*x + 2)**0.3) == '1.28386201800527*(x + 0.869565217391304)**0.3'
+    assert str((2.3*x - 4)**(S(1)/3)) == '1.5874010519682*(0.575*x - 1)**(1/3)'
+    eq = (2.3*x + 4)
+    assert eq**2 == 16.0*(0.575*x + 1)**2
+    assert (1/eq).args == (eq, -1)  # don't change trivial power