Introduction
This guide covers everything you need to know to use simple_fraction effectively. We'll start with the basics and progress to advanced topics.
Why Fractions?
Fractions provide exact representation of rational numbers. Unlike decimals (which approximate 1/3 as 0.333...), fractions store 1/3 as exactly 1/3.
The Classic Example
-- With decimals:
1.0/3.0 + 1.0/3.0 + 1.0/3.0 -- May not equal exactly 1.0
-- With fractions:
create third.make (1, 3)
third + third + third -- Equals exactly 1 (3/3 reduced)
Getting Started
Installation
- Set the environment variable:
# Unix/Linux/macOS export SIMPLE_EIFFEL=/d/prod # Windows set SIMPLE_EIFFEL=D:\prod - Add to your ECF:
<library name="simple_fraction" location="$SIMPLE_EIFFEL/simple_fraction/simple_fraction.ecf"/>
Your First Fraction
local
half: SIMPLE_FRACTION
do
create half.make (1, 2)
print (half.out) -- "1/2"
print (half.to_double.out) -- "0.5"
end
Creating Fractions
From Numerator and Denominator
create half.make (1, 2) -- 1/2
create three_quarters.make (3, 4) -- 3/4
create negative.make (-1, 2) -- -1/2
Automatic Reduction
Fractions are automatically reduced to lowest terms:
create f.make (2, 4) -- Becomes 1/2
create f.make (6, 9) -- Becomes 2/3
create f.make (100, 25) -- Becomes 4
create f.make (3, -4) -- Becomes -3/4 (sign in numerator)
From Integer
create five.make_integer (5) -- 5 (= 5/1)
create neg.make_integer (-3) -- -3
From Mixed Number
Mixed numbers like "2 3/4" are whole + fraction:
create f.make_mixed (2, 3, 4) -- 2 3/4 = 11/4
create f.make_mixed (1, 1, 2) -- 1 1/2 = 3/2
create f.make_mixed (-2, 1, 4) -- -2 1/4 = -9/4
From String
The string parser accepts multiple formats:
create f.make_from_string ("3/4") -- Simple fraction
create f.make_from_string ("-1/2") -- Negative fraction
create f.make_from_string ("2 3/4") -- Mixed number
create f.make_from_string ("5") -- Integer
create f.make_from_string ("0.5") -- Decimal -> 1/2
create f.make_from_string ("0.25") -- Decimal -> 1/4
Special Values
create z.make_zero -- 0
create o.make_one -- 1
Arithmetic Operations
All operations are immutable - they return new fractions without modifying originals.
Basic Operations
local
a, b, r: SIMPLE_FRACTION
do
create a.make (1, 2)
create b.make (1, 4)
r := a + b -- Addition: 1/2 + 1/4 = 3/4
r := a - b -- Subtraction: 1/2 - 1/4 = 1/4
r := a * b -- Multiplication: 1/2 * 1/4 = 1/8
r := a / b -- Division: 1/2 / 1/4 = 2
end
Other Operations
r := f.negate -- Flip sign: 3/4 -> -3/4
r := f.absolute -- Absolute value: -3/4 -> 3/4
r := f.reciprocal -- Flip fraction: 3/4 -> 4/3
r := f.power (2) -- Square: (2/3)^2 = 4/9
r := f.power (-1) -- Negative power = reciprocal
Scaling
-- Multiply by integer
r := f.scale (3) -- 1/4 * 3 = 3/4
-- Divide by integer
r := f.scale_down (2) -- 3/4 / 2 = 3/8
Comparison
SIMPLE_FRACTION implements COMPARABLE:
if a < b then ...
if a <= b then ...
if a > b then ...
if a >= b then ...
if a.is_equal (b) then ...
Status Queries
f.is_zero -- Is 0?
f.is_negative -- Is less than 0?
f.is_positive -- Is greater than 0?
f.is_integer -- Is whole number (denominator = 1)?
f.is_proper -- Is |numerator| < denominator? (like 3/4)
f.is_improper -- Is |numerator| >= denominator? (like 5/4)
f.is_unit_fraction -- Is numerator = 1? (like 1/4)
Mixed Numbers
Mixed numbers combine a whole part with a fractional part, like 2 3/4.
Creating Mixed Numbers
-- From parts
create f.make_mixed (2, 3, 4) -- 2 3/4 = 11/4
-- From string
create f.make_from_string ("2 3/4")
-- Note: internally stored as improper fraction (11/4)
Displaying as Mixed
create f.make (11, 4)
print (f.out) -- "11/4"
print (f.to_mixed_string) -- "2 3/4"
Extracting Parts
create f.make (11, 4)
f.whole_part -- 2 (INTEGER_64)
f.fractional_part -- 3/4 (SIMPLE_FRACTION)
Proper vs Improper
create f.make (3, 4) -- Proper: numerator < denominator
f.is_proper -- True
f.is_improper -- False
create f.make (5, 4) -- Improper: numerator >= denominator
f.is_proper -- False
f.is_improper -- True
Output Formatting
Basic Output
create f.make (3, 4)
f.out -- "3/4"
f.to_string -- "3/4"
create f.make (5, 1)
f.out -- "5" (integers shown without denominator)
Mixed Number Output
create f.make (11, 4)
f.to_mixed_string -- "2 3/4"
create f.make (3, 4)
f.to_mixed_string -- "3/4" (proper fractions unchanged)
Decimal Output
create f.make (3, 4)
f.to_decimal_string (2) -- "0.75"
f.to_decimal_string (4) -- "0.7500"
Numeric Conversion
f.to_double -- Convert to DOUBLE (may lose precision)
f.to_integer -- Convert to INTEGER_64 (truncates)
Factory Helpers
Common fractions available as factory methods:
-- Unit fractions
f.half -- 1/2
f.third -- 1/3
f.quarter -- 1/4
f.zero -- 0
f.one -- 1
-- Multiples of common denominators
f.halves (3) -- 3/2
f.thirds (2) -- 2/3
f.quarters (3) -- 3/4
f.eighths (5) -- 5/8
f.sixteenths (7) -- 7/16
Best Practices
1. Use Fractions for Exact Math
When exactness matters, use fractions:
-- GOOD: Exact
create third.make (1, 3)
total := third + third + third -- Exactly 1
-- AVOID: Approximate
total := 1.0/3.0 + 1.0/3.0 + 1.0/3.0 -- Maybe 0.9999...
2. Convert to Decimal at Display Time
-- Do calculations in fractions
result := (a + b) * c / d
-- Convert only when displaying
print (result.to_decimal_string (2))
3. Use Mixed Numbers for User Display
-- Internal: improper fraction
create f.make (11, 4)
-- Display: mixed number
print (f.to_mixed_string) -- "2 3/4"
4. Handle Edge Cases
-- Check before division
if not divisor.is_zero then
result := amount / divisor
end
-- Check before reciprocal
if not f.is_zero then
r := f.reciprocal
end
Next Steps
- API Reference - Complete feature documentation
- Cookbook - Real-world examples
- Architecture - Internal design