What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use trial division: return False for integers below 2, then test divisors from 2 through math.isqrt(n). If any divisor divides evenly, the number is composite; if none does, it is prime.
The standard Python solution
Python’s math.isqrt() returns the floor of the exact square root for a nonnegative integer and has been available since Python 3.8. Using it avoids floating-point rounding when choosing the loop boundary. See the Python 3.13.5 math documentation.
from math import isqrt
def is_prime(n: int) -> bool:
if n < 2:
return False
for divisor in range(2, isqrt(n) + 1):
if n % divisor == 0:
return False
return True
The + 1 is important. Python’s range excludes its stop value, so without it an exact square such as 49 would never test divisor 7. This function expects an integer. The initial guard also ensures that a negative value is never passed to isqrt, whose argument must be nonnegative.
Why checking only through the square root works
A prime is an integer greater than 1 with no positive divisors other than 1 and itself. For a composite number, factors occur in pairs. If both factors were greater than its square root, their product would be greater than the number. Therefore, every composite integer has at least one factor less than or equal to its square root. Testing that range is sufficient; any larger factor would have a matching smaller factor that the loop would already find. The same factor-pair reasoning is described in this trial-division guide.
#1 Best Overall
What the function returns for boundary values
| Input | Result | Reason |
|---|---|---|
| Negative integer | False |
Prime numbers are positive integers greater than 1. |
| 0 | False |
It is below 2. |
| 1 | False |
It has only one positive divisor, so it is not prime. |
| 2 | True |
No divisor in the tested range divides it. |
| Small composite, such as 9 | False |
3 divides it. |
| Large prime | True |
No divisor through its integer square root divides it. |
Run a complete example
This script reads one value, validates that it is an integer, and prints a clear result.
from math import isqrt
def is_prime(n: int) -> bool:
if n < 2:
return False
for divisor in range(2, isqrt(n) + 1):
if n % divisor == 0:
return False
return True
raw = input("Enter an integer: ").strip()
try:
number = int(raw)
except ValueError:
print("Please enter a whole number, such as 97 or -4.")
else:
print(f"{number} is {'prime' if is_prime(number) else 'not prime'}.")
For example, entering 97 prints 97 is prime.; entering 100 prints 100 is not prime. Converting with int accepts ordinary decimal text, including a leading sign, but rejects values such as 3.14.
How the loop behaves
Early exit for composites
The function returns as soon as it finds a divisor. For 100, divisor 2 is enough; it does not continue testing through 10. This usually makes obvious composites inexpensive.
Worst case for a prime
A prime has no early divisor, so every candidate from 2 through isqrt(n) is tested. The number of modulus operations grows on the order of the square root of n. No performance crossover point for another algorithm is established by the available sources, so measure your actual workload before choosing a more complex method.
Free tools Windows power users keep installed
One-click scans. No signup required.
Why math.sqrt is not the preferred boundary
math.sqrt produces a floating-point value. For sufficiently large integers, converting an inexact float to a loop limit can produce a boundary error. math.isqrt computes an exact integer floor and is the standard-library operation intended for this job. Its behavior and Python 3.8 introduction are documented in the Python 3.11 math documentation and the current documentation linked above.
Rank #2
Small optimization: skip even candidates
After checking 2, every even number can be skipped because an even input greater than 2 is composite. This reduces the number of modulus operations while preserving the same result.
from math import isqrt
def is_prime_skip_evens(n: int) -> bool:
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
for divisor in range(3, isqrt(n) + 1, 2):
if n % divisor == 0:
return False
return True
The straightforward version is often easier to read and is fast enough for occasional checks. Use this variant when profiling shows that repeated single-number checks justify the extra branch; it is not a different primality rule.
Checking many numbers: use a sieve when the limit is known
Running trial division independently for every value repeats the same work. If you need primality results for all integers up to a known maximum, a Sieve of Eratosthenes marks composites once and then answers membership checks in constant time.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstalldef primes_up_to(limit: int) -> list[int]:
if limit < 2:
return []
prime = bytearray(b"x01") * (limit + 1)
prime[0:2] = b"x00x00"
p = 2
while p * p <= limit:
if prime[p]:
prime[p * p : limit + 1 : p] = b"x00" * (((limit - p * p) // p) + 1)
p += 1
return [number for number, is_prime_flag in enumerate(prime) if is_prime_flag]
primes = primes_up_to(100)
print(97 in primes) # True
A sieve uses memory proportional to the upper limit, so it is a poor fit when the maximum is extremely large or when you only need one isolated value. The available guidance recommends choosing between trial division and a sieve based on input count and whether a fixed bound is known; it does not establish a universal size at which one always wins.
Choosing an approach
| Situation | Recommended approach | Trade-off |
|---|---|---|
| One number or occasional checks | Basic is_prime |
Shortest and clearest implementation; up to square-root candidates. |
| Many isolated checks | Odd-candidate variant, after profiling | Fewer tests, with slightly more branching and code. |
| All values through a known maximum | Sieve of Eratosthenes | Reuses work and answers lookups quickly; allocates memory for the range. |
| Cryptographic-size or security-critical inputs | Use a cryptography-focused, reviewed library and its documented primality test | This simple educational function provides no cryptographic assurance, and the available evidence does not identify a particular library or threshold. |
Testing the implementation
Use a table of known values, including boundaries, small factors, squares, and values near the square-root cutoff.
def test_is_prime() -> None:
expected = {
-10: False,
0: False,
1: False,
2: True,
3: True,
4: False,
9: False,
25: False,
29: True,
49: False,
97: True,
}
for number, answer in expected.items():
assert is_prime(number) is answer, number
test_is_prime()
print("All tests passed")
Useful properties to test
- Every input below 2 returns
False. - Every returned
Truevalue is greater than 1. - If a number is reported composite, dividing by at least one integer from 2 through its square root has remainder zero.
- Perfect squares such as 4, 9, 25, and 49 are rejected, confirming that the inclusive
isqrt(n)boundary is tested.
Troubleshooting common mistakes
Returning true for 0 or 1
Starting the loop without an n < 2 guard leaves the range empty for these values, so the function may incorrectly return True. Reject them before the loop.
Missing the square-root endpoint
range(2, isqrt(n)) excludes the endpoint. Use range(2, isqrt(n) + 1); otherwise perfect squares can be misclassified.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsCalling isqrt with a negative value
math.isqrt requires a nonnegative integer. Keep the below-2 guard before the call, or validate input separately if your API accepts other numeric types.
Passing floats
A value such as 7.0 is not an integer input for this function. Decide at the boundary whether to reject floats, accept only values whose integer conversion is exact, or require callers to supply int values. Do not silently truncate a fractional value.
Expecting cryptographic guarantees
Trial division is suitable for learning, ordinary validation, and moderate integers. The available sources do not establish a cryptographic algorithm, security guarantee, or input-size threshold. For key-generation or protocol code, follow the documentation of a dedicated, audited cryptographic package rather than adapting this example.
Or skip the browser setup
If your development workflow also needs clean screenshots of documentation, test pages, or demos, ScreenshotNeo is a website screenshot API and MCP server. It is separate from the Python primality function, but can automate visual checks without configuring a local browser. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and each response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →One GET request returns PNG, JPEG, WebP, or a PDF. The API supports full-page captures with lazy images loaded, CSS-selector element captures, dark mode, device presets and custom viewports, retina scale, PDF paper and margin controls, custom CSS and JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs.
Use the documented endpoint and options at ScreenshotNeo’s API documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
For Python, the equivalent request is:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots, and every feature is available on every plan. Create a free ScreenshotNeo account.
Frequently asked questions
Does this function accept arbitrary Python numeric objects?
No. It is typed and written for integers. Enforce that contract at your input boundary instead of relying on implicit conversion.
Is a sieve always faster?
No. A sieve trades memory and setup work for reuse. It is appropriate when many values share a known upper limit; isolated checks generally need only trial division.
Best Value
Which Python version is required?
The shown implementation requires Python 3.8 or newer because it uses math.isqrt. On older versions, you would need a different exact-integer square-root implementation, but upgrading is the clearer option when possible.
Frequently Asked Questions
Does this function accept arbitrary Python numeric objects?
No. It is intended for integers; validate that contract at your input boundary.
Is a sieve always faster?
No. A sieve uses memory and setup work to reuse results, so it is most useful for many values below a known limit.
Which Python version is required?
The code uses math.isqrt, which was added in Python 3.8.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

