Chapter 3 A
Chapter 3 A
Using numpy for single precision To use single precision, you can use numpy's float32
data type:
10.0
This will explicitly store num as a 32-bit floating-point number. Checking the precision of
a number You can check the size (in bytes) of a floating-point number using itemsize in
numpy:
8
4
If the value of a variable exceeds the largest floating-point number that can be
stored on the computer we say the variable has overflowed.
For instance, if a floating-point variable x holds a number close to the maximum allowed
value of $10^{308}$ and then we execute a statement like “$y =10*x$” it is likely that the
result will be larger than the maximum and the variable y will overflow (but not the
variable x, whose value is unchanged).
In [40]: x=1e308
y=10*x
print(x, y)
1e+308 inf
any smaller than this—if the calculation underflows—the computer will just set the
number to zero.
In [42]: x=1e-308
y=x/1e16
print(x, y)
1e-308 0.0
In [32]: #print(2**1000000)
-128 127
-32768 32767
-2147483648 2147483647
-9223372036854775808 9223372036854775807
Python's built-in int type does not overflow or underflow due to its arbitrary
precision.
Fixed-size integers (e.g., in numpy) can overflow or underflow, and you can check
this using np.iinfo() to get the range of values allowed.
3.141592653589793
3.141592653589793
Both of these methods give a reasonable precision of π for most purposes. If you need
even more precision, you can use specialized libraries like mpmath for arbitrary precisio
3.1415926535897932384626433832795028841971693993751
In [1]: # Expected result should be 0, but due to floating-point inaccuracies, it's not.
result = 0.1 + 0.2 - 0.3
print(f"Result of 0.1 + 0.2 - 0.3: {result}") # This won't print exactly 0
Improving Accuracy: Using the decimal module. The decimal module provides higher
precision for decimal numbers.
The fractions module ensures exact arithmetic as long as the inputs are rational numbers.
Although the precision is not infinite, float128 offers higher accuracy than the standard
float64.
6. Context-Specific Solutions
For specific domains such as scientific computing, using specialized libraries like mpmath
(for arbitrary precision) or scipy can be beneficial. These libraries offer advanced
algorithms to maintain accuracy and improve floating-point precision in mathematical
and scientific computations.
# Set precision
mp.dps = 50 # Set precision to 50 decimal places
mpmath allows for very high precision beyond what decimal offers.
Conclusion
1. Use decimal or fractions for exact arithmetic when dealing with decimals or rational
numbers.
2. Use numpy's higher precision types like float128 for numerical operations.
3. Kahan Summation and similar algorithms can reduce accumulated errors in
summations.
4. Use mathematical reformulation to avoid subtracting nearly equal numbers.
5. math.fsum() provides more accurate summation than sum().
6. Use symbolic libraries like sympy or high-precision libraries like mpmath for more
complex or scientific calculations.
7. Each method improves accuracy in different ways, depending on the problem you
are tackling.
we should assume that all single-precision numbers contain an error in the sixth
decimal place and that all doubles have an error in
1. Using a manual iterative approach You can also calculate the machine epsilon
manually by successively halving a small number until adding it to 1.0 no longer gives a
value different from 1.0:
In [ ]: epsilon = 1.0
while (1.0 + epsilon) != 1.0:
epsilon /= 2
2. Using sys.float_info.epsilon The simplest way is to use the sys module, which
provides system-specific parameters related to floating-point arithmetic:
In [ ]: import sys
epsilon = sys.float_info.epsilon
print(epsilon)
3. Using NumPy If you're using numpy, there's a built-in method to retrieve the machine
epsilon:
In [ ]: import numpy as np
epsilon = np.finfo(float).eps
print(epsilon)
3. Avoiding Over-Precision
In practical terms, trying to compute or compare values beyond machine epsilon can
lead to meaningless results or performance issues. For instance, asking whether two
floating-point numbers are exactly equal is often unreliable due to floating-point
rounding. Instead, comparisons are done within a tolerance range based on epsilon.
When working with operations like subtraction of nearly equal numbers (called
catastrophic cancellation) or matrix inversions, the precision limits defined by epsilon
can help detect potential numerical instability.
Small errors can grow disproportionately in some calculations (like dividing by a very
small number), so understanding machine epsilon allows programmers to design
algorithms that are more stable and avoid amplifying these small errors.
Knowing epsilon helps establish the limits of floating-point arithmetic, ensuring that
results are interpreted correctly. When performing large-scale simulations or
calculations with high precision, understanding the bounds of the machine can
prevent misunderstandings or errors in results.
In summary, machine epsilon plays a critical role in managing and understanding the
limitations of numerical precision in floating-point arithmetic, ensuring that algorithms
are robust, accurate, and reliable within the limits of the system.
Accuracy It tells us how closely the computed value agrees with the true value.
Precision It tells us how closely individual computed values agree with each other.
True Relative Error / Percentage Error $$|e_t| = 100 \% \times \frac{|True - approx|}
{True}$$
if the difference between two numbers is very small, comparable with the error on the
numbers, i.e., with the accuracy of the computer, then the fractional error can become
large and you may have a problem.
Truediff= 1.4142135623730953e-15
diff= 1.3322676295501878e-15
Relative Error= 0.05794452478973511
import numpy as np
N = 1000
beta = 1/100
S = 0.0
Z = 0.0
for n in range(N):
E = n + 0.5
weight = np.exp(-beta*E)
S += weight*E
Z += weight
print(S/Z)
99.95543134093475
3.2 Accuracy Example: Solving Equations
Some algorithms may lose precision when solving certain mathematical problems. For
example, solving a quadratic equation where the discriminant is small.
This example suffers from precision loss for the small discriminant case. You can rewrite it
using a numerically stable method to improve accuracy.
# Using map()
start_time = time.time()
squares = list(map(lambda x: x ** 2, large_list))
end_time = time.time()
print(f"Map function time: {end_time - start_time:.5f} seconds")
This example shows how numpy is significantly faster for vectorized operations
compared to Python lists.
These examples demonstrate how to measure both accuracy and speed in Python, using
different techniques like floating-point arithmetic, loops, vectorization with numpy, and
parallel computing with multiprocessing.
Optimized Kahan Summation Algorithm Inline the code for faster execution: If you don't
need a separate function call, inlining the Kahan summation directly into your main code
helps avoid function call overhead. Minimize operations: Reduce the number of variables
updated or operations repeated in each iteration. Optimized Code Example
# Update sum
sum_ = t
return sum_
# Example usage
numbers = [0.1] * 1000000 # A large list of numbers to sum
result = kahan_summation_optimized(numbers)
print(f"Optimized Kahan summation result: {result}")
Explanation of Optimization
1. Reduced Assignments: The algorithm has minimal assignments and doesn't create
new variables unnecessarily inside the loop.
2. Efficient Calculation: We directly update the sum and the compensation (c) in every
iteration, avoiding redundant computations.
3. Loop Efficiency: The loop remains tight, avoiding unnecessary operations outside of
essential floating-point additions and subtractions.
This optimized Kahan summation will maintain accuracy for summing floating-point
numbers while reducing any performance penalties typically associated with floating-
point arithmetic. It's faster than the unoptimized version, as unnecessary operations are
minimized while keeping the core logic intact.
In [ ]:
5. Minimizing Rounding Errors in Large Calculations
When adding or subtracting many floating-point numbers, rounding errors can
accumulate. Use algorithms designed to minimize these errors, such as Kahan
Summation.
# Example usage
numbers = [0.1, 0.2, 0.3, 0.4]
print(f"Kahan summation result: {kahan_summation(numbers)}")
If you need to calculate $𝑎^2 − 𝑏^2$, instead of directly computing: $𝑎^2 − 𝑏^2 = (𝑎 −
𝑏)(𝑎 + 𝑏)$
This reformulation is numerically stable because it avoids subtracting two large numbers
that are nearly equal.
# Example usage
a = 1000000.001
b = 1000000.0
print(f"Result with reformulation: {difference_of_squares(a, b)}")
In [ ]:
In [ ]:
In [ ]: