Selaa lähdekoodia

Added some numeric division rules.

Taddeus Kroes 14 vuotta sitten
vanhempi
sitoutus
e20e19366d
2 muutettua tiedostoa jossa 62 lisäystä ja 13 poistoa
  1. 60 10
      src/rules/numerics.py
  2. 2 3
      src/strategy.py

+ 60 - 10
src/rules/numerics.py

@@ -1,5 +1,6 @@
 from itertools import combinations
 
+from .utils import greatest_common_divisor
 from ..node import ExpressionLeaf as Leaf, Scope, negate, OP_ADD, OP_DIV, \
         OP_MUL, OP_POW
 from ..possibilities import Possibility as P, MESSAGES
@@ -86,23 +87,39 @@ def match_divide_numerics(node):
 
     Example:
     6 / 2      ->  3
-    3 / 2      ->  3 / 2  # 1.5 would mean a decrease in precision
+    3 / 2      ->  3 / 2      # 1.5 would mean a decrease in precision
     3.0 / 2    ->  1.5
     3 / 2.0    ->  1.5
     3.0 / 2.0  ->  1.5
-    3 / 1.0    ->  3      # Exceptional case: division of integer by 1.0 keeps
-                          # integer precision
+    3 / 1.0    ->  3          # Exceptional case: division of integer by 1.0
+                              # keeps integer precision
+    2 / 4      ->  1 / 2      # denominator % nominator == 0
+    4 / 3      ->  1 + 1 / 3  # nominator > denominator
     """
     assert node.is_op(OP_DIV)
 
     n, d = node
     divide = False
-    dv = d.value
+    nv, dv = n.value, d.value
 
     if n.is_int() and d.is_int():
-        # 6 / 2  ->  3
-        # 3 / 2  ->  3 / 2
-        divide = not divmod(n.value, dv)[1]
+        mod = nv % dv
+
+        if not mod:
+            # 6 / 2  ->  3
+            # 3 / 2  ->  3 / 2
+            return [P(node, divide_numerics, (nv, dv))]
+
+        gcd = greatest_common_divisor(nv, dv)
+
+        if 1 < gcd <= nv:
+            # 2 / 4  ->  1 / 2
+            return [P(node, reduce_fraction_constants, (gcd,))]
+
+        if nv > dv:
+            # 4 / 3  ->  1 + 1 / 3
+            return [P(node, fraction_to_int_fraction,
+                      ((nv - mod) / dv, mod, dv))]
     elif n.is_numeric() and d.is_numeric():
         if d == 1.0:
             # 3 / 1.0  ->  3
@@ -111,14 +128,14 @@ def match_divide_numerics(node):
         # 3.0 / 2  ->  1.5
         # 3 / 2.0  ->  1.5
         # 3.0 / 2.0  ->  1.5
-        divide = True
+        return [P(node, divide_numerics, (nv, dv))]
 
-    return [P(node, divide_numerics, (n.value, dv))] if divide else []
+    return []
 
 
 def divide_numerics(root, args):
     """
-    Combine two constants to a single constant in a division.
+    Combine two divided constants into a single constant.
 
     Examples:
     6 / 2      ->  3
@@ -135,6 +152,39 @@ def divide_numerics(root, args):
 MESSAGES[divide_numerics] = _('Divide constant {1} by constant {2}.')
 
 
+def reduce_fraction_constants(root, args):
+    """
+    Reduce the nominator and denominator of a fraction with a given greatest
+    common divisor.
+
+    Example:
+    2 / 4  ->  1 / 2
+    """
+    gcd = args[0]
+    a, b = root
+
+    return Leaf(a.value / gcd).negate(a.negated) \
+           / Leaf(b.value / gcd).negate(b.negated)
+
+
+MESSAGES[reduce_fraction_constants] = _('Simplify fraction {0}.')
+
+
+def fraction_to_int_fraction(root, args):
+    """
+    Combine two divided integer into an integer with a fraction.
+
+    Examples:
+    4 / 3  ->  1 + 1 / 3
+    """
+    integer, nominator, denominator = map(Leaf, args)
+
+    return integer + nominator / denominator
+
+
+MESSAGES[divide_numerics] = _('Divide constant {1} by constant {2}.')
+
+
 def match_multiply_zero(node):
     """
     a * 0    ->  0

+ 2 - 3
src/strategy.py

@@ -1,4 +1,5 @@
 from rules.sort import move_constant
+from rules.numerics import reduce_fraction_constants
 
 
 def pick_suggestion(possibilities):
@@ -7,12 +8,10 @@ def pick_suggestion(possibilities):
 
     # TODO: pick the best suggestion.
     for suggestion, p in enumerate(possibilities + [None]):
-        if p and p.handler not in [move_constant]:
+        if p and p.handler not in [move_constant, reduce_fraction_constants]:
             break
 
     if not p:
         return possibilities[0]
 
     return possibilities[suggestion]
-
-