Repository: MycroftAI/mycroft-core

Issue:
weirdness pronouncing very large numbers
Seems to be some weirdness for large numbers:

>>> pronounce_number(10000000000)
'one trillion'
>>> pronounce_number(1000000000000)
'one trillion, , , , '

there also seem to be a small cosmetic issue with extra commas:

>>> pronounce_number(1000001)
'one million, , one'

from PR #1646 



Discussion:

Resolving patch:
diff --git a/mycroft/util/lang/format_en.py b/mycroft/util/lang/format_en.py
--- a/mycroft/util/lang/format_en.py
+++ b/mycroft/util/lang/format_en.py
@@ -107,7 +107,7 @@
     (1000, 'thousand'),
     (1000000, 'million'),
     (1e9, "billion"),
-    (1e10, 'trillion'),
+    (1e12, 'trillion'),
     (1e15, "quadrillion"),
     (1e18, "quintillion"),
     (1e21, "sextillion"),
@@ -319,47 +319,48 @@ def _sub_thousand(n):
                     " and " + _sub_thousand(r) if r else "")
 
         def _short_scale(n):
+            if n >= max(SHORT_SCALE_EN.keys()):
+                return "infinity"
             n = int(n)
-            assert 0 <= n
-            return ", ".join(reversed(
-                [_sub_thousand(z) + (
-                    " " + hundreds[i] if i else "") if z else ""
-                 for i, z in enumerate(_split_by_thousands(n))]))
-
-        def _split_by_thousands(n):
             assert 0 <= n
             res = []
-            while n:
-                n, r = divmod(n, 1000)
-                res.append(r)
-            return res
+            for i, z in enumerate(_split_by(n, 1000)):
+                if not z:
+                    continue
+                number = _sub_thousand(z)
+                if i:
+                    number += " "
+                    number += hundreds[i]
+                res.append(number)
+
+            return ", ".join(reversed(res))
 
-        def _split_by_millions(n):
+        def _split_by(n, split=1000):
             assert 0 <= n
             res = []
             while n:
-                n, r = divmod(n, 1000)
+                n, r = divmod(n, split)
                 res.append(r)
             return res
 
         def _long_scale(n):
-            if n >= 10e153:
+            if n >= max(LONG_SCALE_EN.keys()):
                 return "infinity"
             n = int(n)
             assert 0 <= n
             res = []
-            for i, z in enumerate(_split_by_millions(n)):
+            for i, z in enumerate(_split_by(n, 1000000)):
                 if not z:
                     continue
-                number = pronounce_number_en(z, places, True)
-                if i % 2 != 0 and i > 1:
-                    number += " " + "thousand"
-                elif i > 0 and i < 3:
-                    number += " " + hundreds[i] + ","
-                elif i:
-                    number += " " + hundreds[i - 1] + ","
+                number = pronounce_number_en(z, places, True, scientific)
+                # strip off the comma after the thousand
+                if i:
+                    # plus one as we skip 'thousand'
+                    # (and 'hundred', but this is excluded by index value)
+                    number = number.replace(',', '')
+                    number += " " + hundreds[i+1]
                 res.append(number)
-            return " ".join(reversed(res))
+            return ", ".join(reversed(res))
 
         if short_scale:
             result += _short_scale(num)


Test patch:
diff --git a/test/unittests/util/test_format.py b/test/unittests/util/test_format.py
--- a/test/unittests/util/test_format.py
+++ b/test/unittests/util/test_format.py
@@ -186,6 +186,36 @@ def test_convert_scientific_notation(self):
                          "one point six seven two times ten to the power of "
                          "negative twenty seven")
 
+    def test_large_numbers(self):
+        self.assertEqual(
+            pronounce_number(299792458, short_scale=True),
+            "two hundred and ninety nine million, seven hundred "
+            "and ninety two thousand, four hundred and fifty eight")
+        self.assertEqual(
+            pronounce_number(299792458, short_scale=False),
+            "two hundred and ninety nine million, seven hundred "
+            "and ninety two thousand, four hundred and fifty eight")
+        self.assertEqual(
+            pronounce_number(100034000000299792458, short_scale=True),
+            "one hundred quintillion, thirty four quadrillion, "
+            "two hundred and ninety nine million, seven hundred "
+            "and ninety two thousand, four hundred and fifty eight")
+        self.assertEqual(
+            pronounce_number(100034000000299792458, short_scale=False),
+            "one hundred trillion, thirty four thousand billion, "
+            "two hundred and ninety nine million, seven hundred "
+            "and ninety two thousand, four hundred and fifty eight")
+        self.assertEqual(
+            pronounce_number(10000000000, short_scale=True),
+            "ten billion")
+        self.assertEqual(
+            pronounce_number(1000000000000, short_scale=True),
+            "one trillion")
+        # TODO maybe beautify this
+        self.assertEqual(
+            pronounce_number(1000001, short_scale=True),
+            "one million, one")
+
 
 # def nice_time(dt, lang="en-us", speech=True, use_24hour=False,
 #              use_ampm=False):
diff --git a/test/unittests/util/test_parse.py b/test/unittests/util/test_parse.py
--- a/test/unittests/util/test_parse.py
+++ b/test/unittests/util/test_parse.py
@@ -91,7 +91,7 @@ def test_extract_number(self):
         self.assertEqual(extract_number("two million"), 2000000)
         self.assertEqual(extract_number("two million five hundred thousand "
                                         "tons of spinning metal"), 2500000)
-        self.assertEqual(extract_number("six trillion"), 60000000000.0)
+        self.assertEqual(extract_number("six trillion"), 6000000000000.0)
         self.assertEqual(extract_number("six trillion", short_scale=False),
                          6e+18)
         self.assertEqual(extract_number("one point five"), 1.5)