Issue #13201: equality for range objects is now based on equality of the underlying sequences.  Thanks Sven Marnach for the patch.
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index 886cb82..6944e1d 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -1077,6 +1077,13 @@
       >>> r[-1]
       18
 
+   Testing range objects for equality with ``==`` and ``!=`` compares
+   them as sequences.  That is, two range objects are considered equal if
+   they represent the same sequence of values.  (Note that two range
+   objects that compare equal might have different :attr:`start`,
+   :attr:`stop` and :attr:`step` attributes, for example ``range(0) ==
+   range(2, 1, 3)`` or ``range(0, 3, 2) == range(0, 4, 2)``.)
+
    Ranges containing absolute values larger than :data:`sys.maxsize` are permitted
    but some features (such as :func:`len`) will raise :exc:`OverflowError`.
 
@@ -1086,6 +1093,11 @@
       Test integers for membership in constant time instead of iterating
       through all items.
 
+   .. versionchanged:: 3.3
+      Define '==' and '!=' to compare range objects based on the
+      sequence of values they define (instead of comparing based on
+      object identity).
+
 
 .. function:: repr(object)
 
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
index d08ee62..95a5583 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -186,6 +186,12 @@
 (Contributed by Ezio Melotti in :issue:`12753`)
 
 
+Equality comparisons on :func:`range` objects now return a result reflecting
+the equality of the underlying sequences generated by those range objects.
+
+(:issue:`13021`)
+
+
 New, Improved, and Deprecated Modules
 =====================================
 
diff --git a/Lib/test/test_hash.py b/Lib/test/test_hash.py
index fea1025..779e485 100644
--- a/Lib/test/test_hash.py
+++ b/Lib/test/test_hash.py
@@ -107,8 +107,7 @@
         return self.seq[index]
 
 class HashBuiltinsTestCase(unittest.TestCase):
-    hashes_to_check = [range(10),
-                       enumerate(range(10)),
+    hashes_to_check = [enumerate(range(10)),
                        iter(DefaultIterSeq()),
                        iter(lambda: 0, 0),
                       ]
diff --git a/Lib/test/test_range.py b/Lib/test/test_range.py
index ede0791..6035e76 100644
--- a/Lib/test/test_range.py
+++ b/Lib/test/test_range.py
@@ -507,6 +507,58 @@
                 for k in values - {0}:
                     r[i:j:k]
 
+    def test_comparison(self):
+        test_ranges = [range(0), range(0, -1), range(1, 1, 3),
+                       range(1), range(5, 6), range(5, 6, 2),
+                       range(5, 7, 2), range(2), range(0, 4, 2),
+                       range(0, 5, 2), range(0, 6, 2)]
+        test_tuples = list(map(tuple, test_ranges))
+
+        # Check that equality of ranges matches equality of the corresponding
+        # tuples for each pair from the test lists above.
+        ranges_eq = [a == b for a in test_ranges for b in test_ranges]
+        tuples_eq = [a == b for a in test_tuples for b in test_tuples]
+        self.assertEqual(ranges_eq, tuples_eq)
+
+        # Check that != correctly gives the logical negation of ==
+        ranges_ne = [a != b for a in test_ranges for b in test_ranges]
+        self.assertEqual(ranges_ne, [not x for x in ranges_eq])
+
+        # Equal ranges should have equal hashes.
+        for a in test_ranges:
+            for b in test_ranges:
+                if a == b:
+                    self.assertEqual(hash(a), hash(b))
+
+        # Ranges are unequal to other types (even sequence types)
+        self.assertIs(range(0) == (), False)
+        self.assertIs(() == range(0), False)
+        self.assertIs(range(2) == [0, 1], False)
+
+        # Huge integers aren't a problem.
+        self.assertEqual(range(0, 2**100 - 1, 2),
+                         range(0, 2**100, 2))
+        self.assertEqual(hash(range(0, 2**100 - 1, 2)),
+                         hash(range(0, 2**100, 2)))
+        self.assertNotEqual(range(0, 2**100, 2),
+                            range(0, 2**100 + 1, 2))
+        self.assertEqual(range(2**200, 2**201 - 2**99, 2**100),
+                         range(2**200, 2**201, 2**100))
+        self.assertEqual(hash(range(2**200, 2**201 - 2**99, 2**100)),
+                         hash(range(2**200, 2**201, 2**100)))
+        self.assertNotEqual(range(2**200, 2**201, 2**100),
+                            range(2**200, 2**201 + 1, 2**100))
+
+        # Order comparisons are not implemented for ranges.
+        with self.assertRaises(TypeError):
+            range(0) < range(0)
+        with self.assertRaises(TypeError):
+            range(0) > range(0)
+        with self.assertRaises(TypeError):
+            range(0) <= range(0)
+        with self.assertRaises(TypeError):
+            range(0) >= range(0)
+
 
 def test_main():
     test.support.run_unittest(RangeTest)
diff --git a/Misc/ACKS b/Misc/ACKS
index e3e788e..2a62d96 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -613,6 +613,7 @@
 Vladimir Marangozov
 David Marek
 Doug Marien
+Sven Marnach
 Alex Martelli
 Anthony Martin
 Owen Martin
diff --git a/Misc/NEWS b/Misc/NEWS
index 8e6eff7..e6ee120 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@
 Core and Builtins
 -----------------
 
+- Issue #13201: Define '==' and '!=' to compare range objects based on
+  the sequence of values they define (instead of comparing based on
+  object identity).
+
 - Issue #1294232: In a few cases involving metaclass inheritance, the
   interpreter would sometimes invoke the wrong metaclass when building a new
   class object. These cases now behave correctly. Patch by Daniel Urban.
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c
index 58d373c..c1e9e54 100644
--- a/Objects/rangeobject.c
+++ b/Objects/rangeobject.c
@@ -609,6 +609,137 @@
                                        PY_ITERSEARCH_CONTAINS);
 }
 
+/* Compare two range objects.  Return 1 for equal, 0 for not equal
+   and -1 on error.  The algorithm is roughly the C equivalent of
+
+   if r0 is r1:
+       return True
+   if len(r0) != len(r1):
+       return False
+   if not len(r0):
+       return True
+   if r0.start != r1.start:
+       return False
+   if len(r0) == 1:
+       return True
+   return r0.step == r1.step
+*/
+static int
+range_equals(rangeobject *r0, rangeobject *r1)
+{
+    int cmp_result;
+    PyObject *one;
+
+    if (r0 == r1)
+        return 1;
+    cmp_result = PyObject_RichCompareBool(r0->length, r1->length, Py_EQ);
+    /* Return False or error to the caller. */
+    if (cmp_result != 1)
+        return cmp_result;
+    cmp_result = PyObject_Not(r0->length);
+    /* Return True or error to the caller. */
+    if (cmp_result != 0)
+        return cmp_result;
+    cmp_result = PyObject_RichCompareBool(r0->start, r1->start, Py_EQ);
+    /* Return False or error to the caller. */
+    if (cmp_result != 1)
+        return cmp_result;
+    one = PyLong_FromLong(1);
+    if (!one)
+        return -1;
+    cmp_result = PyObject_RichCompareBool(r0->length, one, Py_EQ);
+    Py_DECREF(one);
+    /* Return True or error to the caller. */
+    if (cmp_result != 0)
+        return cmp_result;
+    return PyObject_RichCompareBool(r0->step, r1->step, Py_EQ);
+}
+
+static PyObject *
+range_richcompare(PyObject *self, PyObject *other, int op)
+{
+    int result;
+
+    if (!PyRange_Check(other))
+        Py_RETURN_NOTIMPLEMENTED;
+    switch (op) {
+    case Py_NE:
+    case Py_EQ:
+        result = range_equals((rangeobject*)self, (rangeobject*)other);
+        if (result == -1)
+            return NULL;
+        if (op == Py_NE)
+            result = !result;
+        if (result)
+            Py_RETURN_TRUE;
+        else
+            Py_RETURN_FALSE;
+    case Py_LE:
+    case Py_GE:
+    case Py_LT:
+    case Py_GT:
+        Py_RETURN_NOTIMPLEMENTED;
+    default:
+        PyErr_BadArgument();
+        return NULL;
+    }
+}
+
+/* Hash function for range objects.  Rough C equivalent of
+
+   if not len(r):
+       return hash((len(r), None, None))
+   if len(r) == 1:
+       return hash((len(r), r.start, None))
+   return hash((len(r), r.start, r.step))
+*/
+static Py_hash_t
+range_hash(rangeobject *r)
+{
+    PyObject *t;
+    Py_hash_t result = -1;
+    int cmp_result;
+
+    t = PyTuple_New(3);
+    if (!t)
+        return -1;
+    Py_INCREF(r->length);
+    PyTuple_SET_ITEM(t, 0, r->length);
+    cmp_result = PyObject_Not(r->length);
+    if (cmp_result == -1)
+        goto end;
+    if (cmp_result == 1) {
+        Py_INCREF(Py_None);
+        Py_INCREF(Py_None);
+        PyTuple_SET_ITEM(t, 1, Py_None);
+        PyTuple_SET_ITEM(t, 2, Py_None);
+    }
+    else {
+        PyObject *one;
+        Py_INCREF(r->start);
+        PyTuple_SET_ITEM(t, 1, r->start);
+        one = PyLong_FromLong(1);
+        if (!one)
+            goto end;
+        cmp_result = PyObject_RichCompareBool(r->length, one, Py_EQ);
+        Py_DECREF(one);
+        if (cmp_result == -1)
+            goto end;
+        if (cmp_result == 1) {
+            Py_INCREF(Py_None);
+            PyTuple_SET_ITEM(t, 2, Py_None);
+        }
+        else {
+            Py_INCREF(r->step);
+            PyTuple_SET_ITEM(t, 2, r->step);
+        }
+    }
+    result = PyObject_Hash(t);
+  end:
+    Py_DECREF(t);
+    return result;
+}
+
 static PyObject *
 range_count(rangeobject *r, PyObject *ob)
 {
@@ -763,7 +894,7 @@
         0,                      /* tp_as_number */
         &range_as_sequence,     /* tp_as_sequence */
         &range_as_mapping,      /* tp_as_mapping */
-        0,                      /* tp_hash */
+        (hashfunc)range_hash,   /* tp_hash */
         0,                      /* tp_call */
         0,                      /* tp_str */
         PyObject_GenericGetAttr,  /* tp_getattro */
@@ -773,7 +904,7 @@
         range_doc,              /* tp_doc */
         0,                      /* tp_traverse */
         0,                      /* tp_clear */
-        0,                      /* tp_richcompare */
+        range_richcompare,      /* tp_richcompare */
         0,                      /* tp_weaklistoffset */
         range_iter,             /* tp_iter */
         0,                      /* tp_iternext */