change some numeric behavior
diff --git a/README.md b/README.md
index d8ef7ec45a6..0231599ba25 100644
--- a/README.md
+++ b/README.md
@@ -373,10 +373,11 @@ an adoption helper, avoid using this for new projects.
 
 ### Numeric literals
 
-*Black* standardizes all numeric literals to use lowercase letters: `0xab`
-instead of `0XAB` and `1e10` instead of `1E10`. In Python 3.6+, *Black*
-adds underscores to long numeric literals to aid readability: `100000000`
-becomes `100_000_000`.
+*Black* standardizes most numeric literals to use lowercase letters: `0xab`
+instead of `0XAB` and `1e10` instead of `1E10`. Python 2 long literals are
+styled as `2L` instead of `2l` to avoid confusion between `l` and `1`. In
+Python 3.6+, *Black* adds underscores to long numeric literals to aid
+readability: `100000000` becomes `100_000_000`.
 
 ### Line breaks & binary operators
 
@@ -851,10 +852,13 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
 
 * adjacent string literals are now correctly split into multiple lines (#463)
 
-* code with `_` in numeric literals is recognized as Python 3.6+ (#461)
+* numeric literals are now formatted by *Black* (#452, #461, #464, #469):
 
-* numeric literals are now normalized to include `_` separators on Python 3.6+ code
-  (#452)
+  * numeric literals are normalized to include `_` separators on Python 3.6+ code
+
+  * code with `_` in numeric literals is recognized as Python 3.6+
+
+  * most letters in numeric literals are lowercased (e.g., in `1e10` or `0xab`)
 
 * cache is now populated when `--check` is successful for a file which speeds up
   consecutive checks of properly formatted unmodified files (#448)
diff --git a/black.py b/black.py
index 0f166c61494..3a51f21f4cd 100644
--- a/black.py
+++ b/black.py
@@ -2522,8 +2522,8 @@ def normalize_string_quotes(leaf: Leaf) -> None:
 def normalize_numeric_literal(leaf: Leaf, allow_underscores: bool) -> None:
     """Normalizes numeric (float, int, and complex) literals.
 
-    All letters used in the representation are normalized to lowercase, long number
-    literals are split using underscores.
+    All letters used in the representation are normalized to lowercase (except
+    in Python 2 long literals), and long number literals are split using underscores.
     """
     text = leaf.value.lower()
     if text.startswith(("0o", "0x", "0b")):
@@ -2543,6 +2543,9 @@ def normalize_numeric_literal(leaf: Leaf, allow_underscores: bool) -> None:
     elif text.endswith(("j", "l")):
         number = text[:-1]
         suffix = text[-1]
+        # Capitalize in "2L" because "l" looks too similar to "1".
+        if suffix == "l":
+            suffix = "L"
         text = f"{format_float_or_int_string(number, allow_underscores)}{suffix}"
     else:
         text = format_float_or_int_string(text, allow_underscores)
@@ -2556,14 +2559,22 @@ def format_float_or_int_string(text: str, allow_underscores: bool) -> str:
 
     before, after = text.split(".")
     before = format_int_string(before, allow_underscores) if before else "0"
-    after = format_int_string(after, allow_underscores) if after else "0"
+    if after:
+        after = format_int_string(after, allow_underscores, count_from_end=False)
+    else:
+        after = "0"
     return f"{before}.{after}"
 
 
-def format_int_string(text: str, allow_underscores: bool) -> str:
+def format_int_string(
+    text: str, allow_underscores: bool, count_from_end: bool = True
+) -> str:
     """Normalizes underscores in a string to e.g. 1_000_000.
 
-    Input must be a string of at least six digits and optional underscores.
+    Input must be a string of digits and optional underscores.
+    If count_from_end is False, we add underscores after groups of three digits
+    counting from the beginning instead of the end of the strings. This is used
+    for the fractional part of float literals.
     """
     if not allow_underscores:
         return text
@@ -2573,9 +2584,12 @@ def format_int_string(text: str, allow_underscores: bool) -> str:
         # No underscores for numbers <= 6 digits long.
         return text
 
-    # Avoid removing leading zeros, which are important if we're formatting
-    # part of a number like "0.001".
-    return format(int("1" + text), "3_")[1:].lstrip("_")
+    if count_from_end:
+        # Avoid removing leading zeros, which are important if we're formatting
+        # part of a number like "0.001".
+        return format(int("1" + text), "3_")[1:].lstrip("_")
+    else:
+        return "_".join(text[i : i + 3] for i in range(0, len(text), 3))
 
 
 def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None:
diff --git a/tests/data/numeric_literals.py b/tests/data/numeric_literals.py
index 2dc64c75c8b..b812ebfa824 100644
--- a/tests/data/numeric_literals.py
+++ b/tests/data/numeric_literals.py
@@ -6,6 +6,7 @@
 x = 1.
 x = 1E+1
 x = 1E-1
+x = 1.00000001
 x = 123456789.123456789
 x = 123456789.123456789E123456789
 x = 123456789E123456789
@@ -27,6 +28,7 @@
 x = 1.0
 x = 1e1
 x = 1e-1
+x = 1.000_000_01
 x = 123_456_789.123_456_789
 x = 123_456_789.123_456_789e123_456_789
 x = 123_456_789e123_456_789
diff --git a/tests/data/numeric_literals_py2.py b/tests/data/numeric_literals_py2.py
index 107c39bbaf5..d2db7b0ccc4 100644
--- a/tests/data/numeric_literals_py2.py
+++ b/tests/data/numeric_literals_py2.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python2.7
 
 x = 123456789L
+x = 123456789l
 x = 123456789
 
 # output
@@ -8,5 +9,6 @@
 
 #!/usr/bin/env python2.7
 
-x = 123456789l
+x = 123456789L
+x = 123456789L
 x = 123456789

Closes #467.