Skip to main content

Python float Lab

· 8 min read

Lab: The Floating-Point Trap​

Try running this in your Python terminal to see the logic gap:

  • Step 1: Calculate 0.1 + 0.2.

  • Step 2: Compare it to 0.3.

  • Step 3: Use the decimal module to see the "true" value.

Python

import decimal

# The Trap
print(0.1 + 0.2 == 0.3) # Result: False

# The Reality
print(decimal.Decimal(0.1))
# You will see: 0.1000000000000000055511151231257827021181583404541015625

Lab: Basics & Type Conversion​

Task:

Calculate the total and print its type.

Create a variable price with the value 19.99.

Convert the integer 5 to a float and store it in quantity.

import math

price = 19.99
quantity = float(5)
total = price * quantity
print(f"Total: {total}, Type: {type(total)}")
# Output: Total: 99.95, Type:

Lab: Precision & Rounding​

Use a built-in function to round result to 2 decimal places.

Calculate $0.1 + 0.2$ and store it in result.

Print result. (Note: Observe if it is exactly 0.3).

import math

result = 0.1 + 0.2
print(f"Raw result: {result}")
# Output: 0.30000000000000004 (Due to binary floating-point representation)

rounded_result = round(result, 2)
print(f"Rounded: {rounded_result}")

Why does 0.1 + 0.2 not equal 0.3?

In Python (and most programming languages), floats are represented in binary (base-2). Just as the fraction 1/3 cannot be perfectly represented in decimal (it's 0.3333...), the fraction 1/10 (0.1) cannot be perfectly represented in binary. This leads to the tiny "overflow" you see in the raw result.


Lab: Formatting Output​

Task:

Given pi_approx = 22 / 7, print the value formatted to exactly 3 decimal places using an f-string.

import math
pi_approx = 22 / 7
print(f"Pi to 3 decimal places: {pi_approx:.3f}")

Lab: The math Module​

Task:

Use math.isclose() to check if 0.1 + 0.2 is effectively equal to 0.3.

Import the math module.

Use math.floor() and math.ceil() on the number 4.7.

import math

val = 4.7
print(f"Floor: {math.floor(val)}") # 4
print(f"Ceil: {math.ceil(val)}") # 5

# Checking equality for floats
comparison = math.isclose(0.1 + 0.2, 0.3)
print(f"Is 0.1 + 0.2 close to 0.3? {comparison}")

Lab: The Initialization​

Goal: Create a script that handles user input for a grocery store.

  • Ask the user for the price of an item (e.g., 2.50).

  • Ask for the quantity (e.g., 3).

  • Calculate the total. Even if the user enters "3", ensure the calculation treats it as a float.

  • Bonus: Print the memory address of the float variable using id().

import math

# Using float() to wrap input ensures we don't get a string error
price = float(input("Enter price: ")) # User enters 2.5
quantity = float(input("Enter quantity: ")) # User enters 3
total = price * quantity

print(f"Total: {total}") # Output: 7.5
print(f"Memory ID: {id(total)}")

Lab:​

 The Precision Paradox​

Goal: Demonstrate why developers never use floats for financial calculations.

  • Add 0.1 and 0.2.

  • Compare the result to 0.3 using the == operator.

  • Explain why the result is False using a comment.

import math

result = 0.1 + 0.2
print(f"0.1 + 0.2 is {result}")
# Result: 0.30000000000000004
print(result == 0.3) # Output: False

# Fix: Use math.isclose for floating point comparison
print(math.isclose(result, 0.3)) # Output: True

Lab:​

Advanced Rounding​

Goal: Explore the math module.

  • Given val = 12.51, use three different methods to turn it into a whole number:

  • math.floor()

  • math.ceil()

  • int() conversion.

  • Observe how they differ for the same value.

import math

val = 12.51
print(math.floor(val)) # 12 (Down to nearest integer)
print(math.ceil(val)) # 13 (Up to nearest integer)
print(int(val)) # 12 (Truncates everything after decimal)

Lab:​

Scientific Notation & Large Numbers​

Goal: Work with very small and very large floats.

  • Create a variable atoms equal to 6.022×1023.

  • Create a variable size equal to 0.000000005.

  • Print them and see how Python automatically formats them.

import math

### Solution 4: Scientific Notation
atoms = 6.022e23
size = 5e-9
print(atoms) # 6.022e+23
print(size) # 5e-09

Lab:​

The "Boss Level" Precision (The decimal Module)​

Goal: Fix the floating-point error from Challenge 2 using Python's decimal module.

  • Import Decimal from the decimal module.

  • Create two variables using Decimal, but initialize them with strings ("0.1" and "0.2").

  • Add them together and compare the result to Decimal("0.3").

  • Question: Why must we use strings inside Decimal() instead of raw floats?

from decimal import Decimal

### Solution 5: The Decimal Module
# Using strings ensures the decimal starts exact.
# If you used Decimal(0.1), you'd just be wrapping an imprecise float!
d1 = Decimal("0.1")
d2 = Decimal("0.2")
d_sum = d1 + d2

print(f"Decimal Sum: {d_sum}") # Output: 0.3
print(d_sum == Decimal("0.3")) # Output: True

Lab:​

 Infinity and "Not a Number"​

  • Create a variable inf_val by converting the string "inf" to a float.

  • Create a variable nan_val by converting the string "nan" to a float.

  • Try adding 1 to inf_val. What happens?

from decimal import Decimal

### Solution 6: Infinity and NaN
inf_val = float("inf")
nan_val = float("nan")

print(inf_val + 1) # Output: inf (Infinity plus anything is still infinity)
print(nan_val == nan_val) # Output: False
# EXPLANATION: NaN is never equal to anything, including itself.
# To check for NaN, use math.isnan().

Lab:​

Floating Point Representation​

Goal: See how Python "thinks" about a float under the hood.

  • Take the float 0.125.

  • Use the method .as_integer_ratio() on it.

  • Question: What does this method tell you about how the float is stored?

from decimal import Decimal

val = 0.125
ratio = val.as_integer_ratio()
print(ratio) # Output: (1, 8)
# EXPLANATION: 0.125 is exactly 1/8.
# Since 8 is a power of 2, this float is perfectly precise in binary

 When to use what?​

ScenarioRecommended ToolGeneral Science/PhysicsStandard float (Fast, handles scientific notation well).Money / Accountingdecimal.Decimal (Slow, but 100% accurate to human decimals).Complex Mathmath or cmath module.Massive Data Setsnumpy.float64 (Extremely memory efficient).


Lab:​

Mixed-Type Arithmetic​

Goal: Understand "Coercion" (how Python promotes types).

  • Create an integer a = 5 and a float b = 2.0.

  • Divide a / 2. What is the resulting type?

  • Perform a + b. What is the resulting type?

  • Question: Why does Python choose to turn integers into floats during math instead of the other way around?

import math

### Solution 8: Type Coercion
a = 5
b = 2.0

print(type(a / 2)) # (True division always returns a float)
print(type(a + b)) #

# EXPLANATION: Python "promotes" the integer to a float because floats
# can represent a wider range of values (like decimals).
# Converting a float to an int would lose data (truncation).

Lab:​

Dealing with "Dirty" Strings​

Goal: Clean up data commonly found in web scraping or CSV files.

  • You are given a list of prices as strings: raw_data = ["$12.50", " 100.99 ", "N/A", "5.00"].

  • Loop through the list and:

  • Strip the $ sign.

  • Remove extra whitespace.

  • Skip or handle strings like "N/A" so the code doesn't crash.

  • Convert the valid prices to floats and sum them.

import math

raw_data = ["$12.50", " 100.99 ", "N/A", "5.00"]
clean_prices = []

for item in raw_data:
try:
# Clean the string
processed = item.replace("$", "").strip()
# Attempt conversion
clean_prices.append(float(processed))
except ValueError:
print(f"Skipping invalid data: {item}")

print(f"Total: {sum(clean_prices)}") # Output: 118.49

Lab:​

The fsum Advantage​

Goal: Learn how to sum a large list of floats without losing a single cent.

  • Create a list: values = [0.1] * 10.

  • Sum them using the standard sum(values).

  • Sum them using math.fsum(values).

  • Compare the results.

import math

values = [0.1] * 10

standard_sum = sum(values)
precise_sum = math.fsum(values)

print(f"Standard: {standard_sum}") # Output: 0.9999999999999999
print(f"fsum: {precise_sum}") # Output: 1.0

# EXPLANATION: math.fsum tracks the "lost" precision bits during
# each addition, making it superior for summing long lists of floats.

Lab:​

Bits and Bytes​

Goal: Visualize how a float looks in its hex (hexadecimal) form.

  • Python floats have a .hex() method. Take the float 2.5 and 0.1 and print their hex strings.

  • Question: Why is the hex for 2.5 much shorter and "cleaner" than the hex for 0.1?

import math

### Solution 11: Hex Representation
print((2.5).hex()) # Output: '0x1.4000000000000p+1'
print((0.1).hex()) # Output: '0x1.999999999999ap-4' (Notice the repeating '9999...')

# EXPLANATION: 2.5 is a "dyadic" rational (the denominator is a power of 2),
# so it terminates in binary. 0.1 repeats infinitely, just like 1/3 in decimal.

Lab:​

Comparison with Epsilon​

Goal: Understand the "smallest possible" difference.

  • In numerical computing, we often compare a difference to a tiny value called Epsilon.

  • Calculate the absolute difference between (0.1 + 0.2) and 0.3.

  • Check if this difference is smaller than 1e-15.

import math

diff = abs((0.1 + 0.2) - 0.3)
epsilon = 1e-15

print(f"Difference: {diff}")
print(f"Is it negligible? {diff < epsilon}") # Output: True

# NOTE: This is essentially what math.isclose() does under the hood.

Lab:​

List Filtering & Overflow​

Goal: Handle a list containing "broken" float data.

  • Create a list: data = [1.5, float('inf'), 2.2, float('nan'), 3.7, -float('inf')].

  • Write a list comprehension to create a new list that only contains finite, real numbers (no inf or nan).

  • Hint: Use math.isfinite().

### Solution 13: Filtering with math.isfinite()
data = &#91;1.5, float('inf'), 2.2, float('nan'), 3.7, -float('inf')]

# math.isfinite() returns False for NaN and both positive/negative Infinity
clean_data = &#91;x for x in data if math.isfinite(x)]

print(f"Cleaned Data: {clean_data}") # Output: &#91;1.5, 2.2, 3.7]