What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Calling int() on a float does not round. It discards the fractional part, moving toward zero, and it raises no warning. If a risk rule compares the converted value with a limit, that discarded fraction can decide whether a transaction, score or count is flagged. The headline describes exactly this kind of failure, but no public record independently confirms the specific system it describes. This guide therefore treats the headline as a failure pattern: what the conversion does, how it changes a threshold decision, where similar behavior has been documented, and how to find and fix it in your own code.
What int() actually does to a float
Python’s built-in types documentation states that conversion from float to int truncates, discarding the fractional part. Truncation means rounding toward zero. Three consequences matter for risk logic:
- Values just below a whole number fall to the lower integer, so
999.99becomes999. - Values just above a whole number also fall to the lower integer, so
1000.75becomes1000. - Negative fractions move toward zero, so
-0.75becomes0, not-1.
The table below compares int() with the rounding functions that developers often assume are equivalent. The last row shows a float that is not exactly what its decimal spelling suggests.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →| Input (float) | int() |
round() |
math.floor() |
Notes |
|---|---|---|---|---|
| 999.99 | 999 | 1000 | 999 | round() uses round-half-to-even at exact .5 values |
| 1000.75 | 1000 | 1001 | 1000 | Fraction removed without any signal |
| -0.75 | 0 | -1 | -1 | Truncation toward zero differs from floor for negatives |
| 0.29 * 100 (stored as 28.999999999999996) | 28 | 29 | 28 | The binary float result is just below 29 |
None of these results is a bug in Python. Each follows the documented rule. The problem arises when a risk rule assumes the integer means something it does not.
#1 Best Overall
How a threshold check quietly changes its answer
Consider a rule that flags any order above 1000 units. The developer converts the amount to an integer first, perhaps because a downstream field expects whole numbers:
LIMIT = 1000
def needs_review(amount):
return int(amount) > LIMIT
print(needs_review(1000.75)) # False: 1000.75 exceeds the limit, but the flag is not raised
print(needs_review(1001.0)) # True
The first call returns False because the fraction was removed before the comparison ran. Anyone reading the rule would expect 1000.75 to be flagged. The code gives no error, no log line and no exception, so the failure only appears when someone tests the boundary or reviews a rejected transaction.
The same mechanism can disable a control that depends on a small value. A rule such as “count events where the score is at least 1” would never count a score of 0.99, because int(0.99) is 0.
Rank #2
Where this pattern has been documented
A payment amount that lost a cent
Python issue tracker issue 27697, opened on 2016-08-05, records a case in which a payment amount was formatted for processing and converted through floating-point arithmetic. The issue author, Nathan Snobelen, reported: “We have some payment code which formats numbers for processing in our system and we noticed that the payment of 1108431.38 was dropped by a penny to 1108431.37.” The report is a historical account of one code path. It shows the mechanism clearly, but it does not prove that every multiplication by 100 fails, and it does not describe any risk system.
C integer conversion paths that used __int__
Python issue tracker issue 36048, opened on 2019-02-20 and later closed, discusses implicit integer conversions at C-API boundaries. The discussion concerns paths that could call __int__ and truncate non-integral Decimal or Fraction values. Behavior in these paths has changed across Python releases, so confirm the behavior of your target interpreter before relying on any specific version claim.
Why the float is the root cause
Two separate steps can remove the fraction. First, arithmetic on binary floats can produce a value that is slightly below the decimal result you expected. Second, int() discards whatever remains. A price of 0.29 multiplied by 100 is a common example: the stored result is just below 29, so int() returns 28. A check that depends on exact cents then sees a lower amount than the customer paid.
Keeping the amount as a Decimal from a string avoids the first step. The decimal module’s documentation explains that Decimal("3.14") represents the decimal value written in the string, while Decimal(3.14) captures the exact binary value of the float, which may contain many digits beyond what you typed.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →from decimal import Decimal
Decimal("0.29") * 100 # Decimal('29.00')
int(Decimal("0.29") * 100) # 29
Decimal(0.29) * 100 # long binary expansion, not 29
Note that int() still truncates a Decimal with a fractional part. Switching types removes the representation error but does not choose a rounding policy for you.
Choose the rounding rule before the conversion
Each option encodes a different policy. Pick the one your rule specifies, and make the choice visible in code.
| Approach | Input representation | Rounding rule | Behavior at x.5 or fractional input | Auditability |
|---|---|---|---|---|
int(float_value) |
Binary float | Truncation toward zero | Fraction silently discarded | Low: the rule is implicit |
int(Decimal("...")) |
Decimal from a string | Truncation toward zero | Fraction silently discarded | Medium: exact input, but policy still implicit |
Decimal("...").quantize(Decimal("1"), rounding=ROUND_HALF_UP) |
Decimal from a string | Explicit rounding mode | Rounds as declared | High, especially with a trapped Inexact signal |
round(float_value) |
Binary float | Round half to even | x.5 values go to the even neighbor | Medium: the tie rule is easy to miss |
math.floor() / math.ceil() |
Float or Decimal | Toward negative or positive infinity | Consistent direction for negatives | High when the direction is the intended policy |
The decimal context offers signals such as Inexact and Rounded. These can be trapped so that an operation which discards digits raises an exception instead of silently continuing. This is useful for money, where an unexpected cent should stop processing rather than disappear.
from decimal import Decimal, ROUND_HALF_UP, getcontext, Inexact
getcontext().traps[Inexact] = True
amount = Decimal("1000.75")
amount.quantize(Decimal("1"), rounding=ROUND_HALF_UP) # Decimal('1001'), explicit policy
amount.quantize(Decimal("1"), rounding=None) if False else None
Find the conversions in your own code
Use this sequence on any risk path where a float enters a comparison.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minute- Search the risk module for integer conversions:
grep -rn "int(" src/risk/. Adjust the path to your repository layout, and include the modules that parse input, such as JSON or form handlers. - Log the value at each stage with its type:
print(repr(amount), type(amount)). A value that prints as1000.7499999999999is a sign that binary representation is involved. - Test values on both sides of each threshold, such as
999.999,1000.0,1000.001and, if negative values are valid in your domain,-0.5. Record the decision for each input. - Check whether the integer is later compared with a fractional limit, stored as money, or used as a count. Each use is a place where the fraction matters.
- Confirm the interpreter version with
python3 --versionand read the behavior notes for that release before assuming an implicit conversion works the same way everywhere.
When the fix is in place, add a regression test for each boundary value in step 3. A single assertion such as assert needs_review(1000.75) is True makes a silent truncation visible in the test run.
Best Value
What the digit limit does and does not cover
CPython limits conversions between very long decimal strings and integers. The limit exists because converting extremely large values can consume substantial CPU time, which matters when the input is untrusted or when a large integer is written back as a string during logging or serialization. The CPython security FAQ for CVE-2020-10735 documents this rationale. This is a denial-of-service safeguard, and it is unrelated to losing a fractional part in int(float_value). Disabling it will not change a risk decision, so do not treat it as a remedy for this failure.
Checklist for risk code that uses integer conversion
- Every
int()call on a value that can be fractional has a stated rounding or rejection policy in a comment or function name. - Monetary amounts are built from strings or validated decimal input, not from float arithmetic.
- Inputs that should be whole numbers are rejected when they are not, rather than truncated.
- Boundary tests exist on both sides of every threshold, including fractional values just above and below the limit.
- Logs record the original value and its type alongside the decision, so a reviewer can see what the rule received.
The conversion itself is not the defect. The defect is an unstated policy that the conversion enforces without anyone choosing it.
”
The Bottom Line
A single int() on a float is safe only when truncation toward zero is the rule you actually want. For thresholds, money and counts, state the rounding policy explicitly, build decimal values from strings, and test both sides of every boundary.
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.

