[Rod Stephens Books]
Index Books Python Examples About Rod Contact
[Mastodon] [Bluesky] [Facebook]
[Build Your Own Python Action Arcade!]

[Build Your Own Ray Tracer With Python]

[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

Title: Learn about numeric data types (and the number 998,001) in Python

[The value 1 / 998001 produces a sequence of every three-digit number from 000 to 999 in order except 998]

This is one of those examples where I stumbled across an interesting numeric fact online and I decided to verify it. Along the way, we need to learn a bit about floating point numbers and precision in Python.

The fact is that, if you calculate 1 / 998,001, you get a repeating sequence of digits after the decimal point that include every three-digit sequence 000, 001, 002, ..., 999 in order with 998 omitted. The value 998,001 happens to be 9992 and for some reason, it is often called a palindromic number even though it clearly is not.

The following sections show three ways you can try to verify the three-digit sequences.

Floating Point

The most obvious thing to try is to divide 1 by 998,001 and display the result as in the following code.

value = 1 / 998001 print(f'{value:.25f}')

This code sets value equal to 1 / 998001 and prints the result. The print statement only prints 25 digits after the decimal point because that's enough to see that the result is incorrect.

Here's the output.

0. 0000010020030040050059553

12345678901234567890 1234567890 This starts off well with 000, 001, 002, 003, 004, and 005, but then lack of precision makes it veer off course. The next set of digits 0059 are close to 006 but everything after that is gibberish.

The problem is that Python's floating point data type doesn't have enough precision to store the result more correctly. It uses 64 bits so it can only reliably give you around 15 to 17 digits of precision. There are a few things you can do about that.

Integers

Python integers have unlimited precision so you can make integers as long as you like. That gives us one workaround for this problem. Multiply the numerator by a power of ten big enough for us to see all of the digits we want and then perform integer division. The result is the same as the original problem multiplied by the power of ten so all of those digits lie to the left of the decimal point.

Python can calculate the result, but it won't convert it into a string because it's too long. Fortunately, we can use sys.set_int_max_str_digits to increase the number of digits Python will convert into a string.

Here's the new code.

import sys # Increase the limit for integer-to-string conversion. sys.set_int_max_str_digits(0) power = 3000 numerator = 1 * 10**power denominator = 998001 result = numerator // denominator print(f'{result}') result_string = f'00000{result}' check_result(result_string)

This code imports the sys library and then uses sys.set_int_max_str_digits(0) to make Python convert any number of digits into as string.

Next, the code sets numerator to 103000, sets denominator to 998001, and divides numerator by denominator. It's important that the code uses integer division because, if you use floating point division, the result is too big to fit in a float.

The program then prints the result. To verify the result, it converts result into a string and passes it into the following check_result function.

def check_result(result): # Remove leading 0. if present. result = result.replace('0.', '') for i in range(3000 // 3): str = f'{i:03}' substr = result[3*i:3*i+3] if str != substr: print(f'{str} != {substr}')

The check_result strips off the leading "0." if it's there. It then loops through the remaining digits three at a time to verify that they follow the pattern 000, 001, 002, etc. If a digit substring doesn't match the expected triplet, it prints a message. I was too lazy to skip the missing 998 triplet, so the function should flag that one and the following one 999 (because its position is shifted by the missing 998).

Here's the abbreviated output from the earlier code that uses integer division. p class="output">1002003004005006007008009010011012013014015016017018019020021022023024025 0260270280290300310320330340350360370380390400410420430440450460470480490 ... 5976977978979980981982983984985986987988989990991992993994995996997999000 998 != 999 999 != 000

The result begins with 1 because it is an integer and drops leading zeros. If you look at the line after the ellipsis, you'll see that it ends with 996, 997, 999, and 000 so the 998 triplet is missing as advertised.

Decimal

Another approach is to use the Decimal class, which provides decimal calculations with a given decimal precision. Here's the previous example converted to use Decimal.

from decimal import Decimal, getcontext # Increase the limit for integer-to-string conversion. sys.set_int_max_str_digits(0) # Set Decimal precision to 3000 digits. getcontext().prec = 3000 # Perform the division result = Decimal(1) / Decimal(998001) print(result) result_string = f'{result}' check_result(result_string)

Like the previous version, this code has trouble converting its result into a string with enough digits, so it also calls sys.set_int_max_str_digits to allow Python to use any number of digits in a string conversion.

It then calls getcontext().prec = 3000 to tell the Decimal class to use 3,000 decimal digits of precision in its calculations.

The program then makes Decimal representing 1 and 998001 and divides them. It prints the result, converts the result into a string, and uses check_result to verify the result.

Here's the abbreviated output.

0.000001002003004005006007008009010011012013014015016017018019020021022023024025 02602702802903003103203303403503603703803904004104204304404504604704804905005105 ... 97597697797897998098198298398498598698798898999099199299399499599699799900000100 998 != 999 999 != 000

Unlike the previous result, which used integers, this result begins with "0." followed by 000, 001, etc. Like the previous result, it ends with 996, 997, 999, and then repeats 000, 001, etc.

Conclusion

This example verifies the weird property that 1 / 998001 produces the sequence 000, 001, 002, ..., 996, 997, 999. More importantly it demonstrates two techniques for working with many digits after the decimal point. First, it shows how you can sometimes multiply numbers by a power of ten and then use integer arithmetic to get the same result as an integer. Second, it shows how you can use the Decimal class to work with an arbitrary number of decimal digits.

Download the example to experiment with it and to see additional details.

© 2025 Rocky Mountain Computer Consulting, Inc. All rights reserved.