Repository: sympy/sympy

Issue:
Printing multiplication by negative number with custom (infix) function not correctly parenthesized.
I am trying to define a custom function with lower precedence than multiplication. However, whenever there is a negative number involved, the parentheses are not there anymore.

-----

**Custom function:**
```python
class F(sympy.Function):
    precedence = 45

    def _sympystr(self, printer):
        return f"{printer._print(self.args[0])} F {printer._print(self.args[1])}"
```

**Printing:**
```python
>>> a, b = sympy.symbols("a b")

>>> 2 * F(a, b)
2*(a F b)

>>> -2 * F(a, b)
-2*a F b  # <-------------- No parentheses!
          # Expected: -2*(a F b)
```

-----

Although I am able to get around that, this is a bug, right?

Discussion:

Fix (patch):
diff --git a/sympy/printing/precedence.py b/sympy/printing/precedence.py
index 563a04b349..d22d5746ae 100644
--- a/sympy/printing/precedence.py
+++ b/sympy/printing/precedence.py
@@ -59,6 +59,11 @@
 
 
 def precedence_Mul(item):
+    from sympy.core.function import Function
+    if any(hasattr(arg, 'precedence') and isinstance(arg, Function) and
+           arg.precedence < PRECEDENCE["Mul"] for arg in item.args):
+        return PRECEDENCE["Mul"]
+
     if item.could_extract_minus_sign():
         return PRECEDENCE["Add"]
     return PRECEDENCE["Mul"]


Test changes:
diff --git a/sympy/printing/tests/test_precedence.py b/sympy/printing/tests/test_precedence.py
index 372a5b0356..d08ea07483 100644
--- a/sympy/printing/tests/test_precedence.py
+++ b/sympy/printing/tests/test_precedence.py
@@ -1,6 +1,6 @@
 from sympy.concrete.products import Product
 from sympy.concrete.summations import Sum
-from sympy.core.function import Derivative
+from sympy.core.function import Derivative, Function
 from sympy.core.numbers import Integer, Rational, Float, oo
 from sympy.core.relational import Rel
 from sympy.core.symbol import symbols
@@ -87,3 +87,42 @@ def test_And_Or():
     assert precedence(x & y) == PRECEDENCE["And"]
     assert precedence(x | y) == PRECEDENCE["Or"]
     assert precedence(~y) == PRECEDENCE["Not"]
+
+
+def test_custom_function_precedence_comparison():
+    """
+    Test cases for custom functions with different precedence values,
+    specifically handling:
+    1. Functions with precedence < PRECEDENCE["Mul"] (50)
+    2. Functions with precedence = Func (70)
+
+    Key distinction:
+    1. Lower precedence functions (45) need parentheses: -2*(x F y)
+    2. Higher precedence functions (70) don't: -2*x F y
+    """
+    class LowPrecedenceF(Function):
+        precedence = PRECEDENCE["Mul"] - 5
+        def _sympystr(self, printer):
+            return f"{printer._print(self.args[0])} F {printer._print(self.args[1])}"
+
+    class HighPrecedenceF(Function):
+        precedence = PRECEDENCE["Func"]
+        def _sympystr(self, printer):
+            return f"{printer._print(self.args[0])} F {printer._print(self.args[1])}"
+
+    def test_low_precedence():
+        expr1 = 2 * LowPrecedenceF(x, y)
+        assert str(expr1) == "2*(x F y)"
+
+        expr2 = -2 * LowPrecedenceF(x, y)
+        assert str(expr2) == "-2*(x F y)"
+
+    def test_high_precedence():
+        expr1 = 2 * HighPrecedenceF(x, y)
+        assert str(expr1) == "2*x F y"
+
+        expr2 = -2 * HighPrecedenceF(x, y)
+        assert str(expr2) == "-2*x F y"
+
+    test_low_precedence()
+    test_high_precedence()