Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Floating Point Numbers comparison #203 #496

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions data/learning.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ books:
- link: /learn/quickstart/organising_code
- link: /learn/quickstart/derived_types

- title: Floating Point Numbers comparison
description: Learn how to handle rounding errors in floating-point numbers, use them in if and for loops, and make robust comparisons using tolerance in Fortran.
category: Getting started
link: /learn/Floating_Point_Numbers_comparison
saikarna913 marked this conversation as resolved.
Show resolved Hide resolved

- title: Building programs
description: How to use the compiler to build an executable program
category: Getting started
Expand Down
77 changes: 77 additions & 0 deletions source/learn/Floating_Point_Numbers_comparison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Floating-Point Tolerance and Precision in Fortran

Floating-point numbers like `0.1` cannot be represented exactly in binary because their binary form is infinite and repeating. Due to the limited precision of floating-point formats (like 32-bit or 64-bit), these numbers are rounded off to fit within the constrained number of bits.
This rounding can lead to small errors in representation and calculations.

To ensure reliable comparisons, it is better to use **tolerance** to check whether two numbers are close enough rather than comparing them directly.

## Handling Floating-Point Comparisons

Here’s an example of how to use a tolerance value in Fortran:

### Example: Using Tolerance
```fortran
real(dp) :: tol
tol = 10 * epsilon(1.0_dp)

real(dp), parameter :: tol = 1.0e-10_dp
if (abs(x - y) < tol) then
print *, "Effectively Equal"
else
print *, "Not Equal"
end if
saikarna913 marked this conversation as resolved.
Show resolved Hide resolved
```

In this example:
- The **tolerance** value is derived using either `epsilon()` or a manually defined small value.
- Instead of checking `x == y`, we compare the absolute difference `abs(x - y)` to the tolerance.

---

## Avoiding Floating-Point Precision Issues

Sometimes, directly incrementing floating-point numbers can cause cumulative rounding errors.
Instead, use **integer iterators** and convert them to floating-point values within the loop.

### Example: Using Integer Iterators
```fortran
integer :: i
real(dp) :: step, value
step = 0.1_dp

do i = 0, 10
value = i * step
print *, value
end do
```

In this example:
- The step size is defined as `0.1` in double precision.
- The loop uses integers (`i`) to avoid compounding errors when iterating.

---

## Why Use Tolerance?

Due to rounding errors, numbers like `0.1 + 0.2` may not exactly equal `0.3`. Direct comparisons fail in such cases:
```fortran
if (a + b == c) then
print *, "Equal"
else
print *, "Not Equal"
end if
```
Instead, use a tolerance to make approximate comparisons:
```fortran
if (abs((a + b) - c) < tol) then
print *, "Approximately Equal"
else
print *, "Not Equal"
end if
```

---