Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions mathics/builtin/arithfns/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,6 @@ class Power(InfixOperator, MPMathFunction):

mpmath_name = "power"

messages = {
"infy": "Infinite expression `1` encountered.",
"indet": "Indeterminate expression `1` encountered.",
}

nargs = {2}
rules = {
"Power[]": "1",
Expand Down
91 changes: 79 additions & 12 deletions mathics/builtin/intfns/divlike.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""

import sys
from typing import List, Optional
from typing import List, Optional, Union

import sympy
from sympy import Q, ask
Expand All @@ -25,12 +25,19 @@
from mathics.core.convert.python import from_bool
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.symbols import Symbol
from mathics.core.systemsymbols import (
SymbolComplexInfinity,
SymbolIndeterminate,
SymbolQuotient,
SymbolQuotientRemainder,
)
from mathics.eval.intfns.divlike import eval_GCD, eval_LCM, eval_ModularInverse
from mathics.eval.intfns.divlike import (
eval_GCD,
eval_LCM,
eval_ModularInverse,
eval_Quotient,
)


class CompositeQ(Builtin):
Expand Down Expand Up @@ -294,34 +301,94 @@ def eval(self, a: Integer, b: Integer, m: Integer, evaluation: Evaluation):

class Quotient(Builtin):
"""
<url>:WMA link:https://reference.wolfram.com/language/ref/Quotient.html</url>
<url>:Quotient:https://en.wikipedia.org/wiki/Quotient</url> (<url>
:WMA link:https://reference.wolfram.com/language/ref/Quotient.html</url>)

<dl>
<dt>'Quotient[m, n]'
<dd>computes the integer quotient of $m$ and $n$.
<dd>computes the integer quotient of $m$ and $n$. For non-complex numbers, this \
equivalent to 'Floor[m/n]'. When a complex number is involved, it is 'Round[m/n]'.
<dt>'Quotient[m, n, d]'
<dd>computes the integer quotient of $m-d$ and $n$. For non-complex numbers, this \
is equivalent to 'Floor[(m-d)/n]'. When a complex number is involved, it is \
'Round[(m-d)/n]'.
</dl>

## Plot showing the step-like 'Floor' behavior of 'Quotient':
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a bad bug that recently popped up involving the interaction of args checking and things that wrap arguments in a sequence, like DiscretePlot, which uses compile_function_quiet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rocky, would you put an issue with this example, to look at it later?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I'm not sure exactly what's up, but this seems like a nasty bug.

##
## >> DiscretePlot[Quotient[n, 5], {n, 30}]
## = -Graphics-

Integer-argument 'Quotient':
>> Quotient[23, 7]
= 3

Rational-argument 'Quotient':
>> Quotient[19/3, 5/2]
= 2

'Quotient' with inexact numbers:
>> Quotient[4.56, 2.5]
= 1

'Quotient' with two complex numbers is same as 'Round[m/n]':
>> Quotient[10.4 + 8 I, 4. + 5 I]
= 2

'Quotient' for large integers:
>> Quotient[10^90, NextPrime[10^80]]
= 9999999999

'Quotient' threads elementwise over lists:
>> Quotient[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 3]
= {0, 0, 1, 1, 1, 2, 2, 2, 3, 3}
"""

attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED
eval_error = Builtin.generic_argument_error
expected_args = (2, 3)

messages = {
"infy": "Infinite expression `1` encountered.",
rules = {
"Quotient[m_Complex, n_?NumberQ]": "Round[m / n]",
"Quotient[m_?NumberQ, n_Complex]": "Round[m / n]",
"Quotient[l_List, n_?NumberQ]": "Map[Quotient[#, m] &, l]",
"Quotient[l_List, n_?NumberQ, d_?NumberQ]": "Map[Quotient[#, m, d] &, l]",
}
summary_text = "integer quotient"

def eval(self, m: Integer, n: Integer, evaluation: Evaluation):
"Quotient[m_Integer, n_Integer]"
summary_text = "compute integer quotient"

def eval(self, m, n, evaluation: Evaluation) -> Union[Symbol, Integer]:
"Quotient[m_?NumberQ, n_?NumberQ]"
py_m = m.value
py_n = n.value
if py_n == 0:
if py_m == 0:
tag = "indet"
result = SymbolIndeterminate
else:
tag = "infy"
result = SymbolComplexInfinity
evaluation.message("Quotient", tag, Expression(SymbolQuotient, m, n))
return result
return eval_Quotient(py_m, py_n, 0)

def eval_with_offset(
self, m, n, d, evaluation: Evaluation
) -> Union[Symbol, Integer]:
"Quotient[m_?NumberQ, n_?NumberQ, d_?NumberQ]"
py_m = m.value
py_n = n.value
py_d = d.value
if py_n == 0:
evaluation.message("Quotient", "infy", Expression(SymbolQuotient, m, n))
return SymbolComplexInfinity
return Integer(py_m // py_n)
if py_m - py_d == 0:
tag = "indet"
result = SymbolIndeterminate
else:
tag = "infy"
result = SymbolComplexInfinity
evaluation.message("Quotient", tag, Expression(SymbolQuotient, m, n, d))
return result
return eval_Quotient(py_m, py_n, py_d)


class QuotientRemainder(Builtin):
Expand Down
1 change: 1 addition & 0 deletions mathics/builtin/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class General(Builtin):
"Single or list of non-negative integers expected at " "position `1`."
),
"indet": "Indeterminate expression `1` encountered.",
"infy": "Infinite expression `1` encountered.",
"innf": "Non-negative integer or Infinity expected at position `1` in `2`",
"int": "Integer expected.",
"intp": "Positive integer expected.",
Expand Down
4 changes: 4 additions & 0 deletions mathics/eval/intfns/divlike.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ def eval_ModularInverse(k: int, n: int) -> Optional[Integer]:
except ValueError:
return
return Integer(r)


def eval_Quotient(m, n, d) -> Integer:
return Integer((m - d) // n)
14 changes: 13 additions & 1 deletion test/builtin/intfns/test_divlike.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,19 @@
"Quotient[13, 0]",
("Infinite expression Quotient[13, 0] encountered.",),
"ComplexInfinity",
None,
"Check Quotient two-argument divide by 0 error result",
),
(
"Quotient[1, 0, 1]",
("Indeterminate expression Quotient[1, 0, 1] encountered.",),
"Indeterminate",
"Check Quotient three-argument 0/0 error result",
),
(
"Quotient[0, 0]",
("Indeterminate expression Quotient[0, 0] encountered.",),
"Indeterminate",
"Check Quotient two-argument 0/0 error",
),
("Quotient[-17, 7]", None, "-3", None),
("Quotient[-17, -4]", None, "4", None),
Expand Down
Loading