The Ancient Greek polymath Eratosthenes of Cyrene made the first serious attempt at calculating the size of the Earth. Using very simple observations and mathematics he achieved a surprisingly accurate result and in this article I will replicate his calculations in Python.

## Eratosthenes and Earth

Eratosthenes of Cyrene (*c 276BC to c 195/194BC*) was chief librarian at the legendary Library of Alexandria. When he wasn't busy frowning and tutting at people for making a noise he took time out to calculate the size of the Earth.

He was aware that at the Summer Solstice (the time when the Sun is at its highest point in the sky) the Sun could be seen reflected in the water at the bottom of a deep well in Syene (now called Aswan, and not to be confused with Cyrene), meaning it was exactly overhead. At home in Alexandria, some way north of Syene, the Sun never gets this high so will never be reflected by the water in a well, and will always cast a shadow to the north of any object it shines on.

The diagram below represents a cross-section of a quarter of the Earth, with Syene and Alexandria at their correct latitudes. I have used poles instead of wells, and if you look at the second zoomed-in view you can see that at Alexandria the Sun casts a shadow, specifically one of 7° 12′ (7 degrees 12 minutes, or 1/60 of a degree) so this is the difference between the two latitudes.

A closer look.

7° 12′ happens to be exactly 1/50 of 360°, meaning the distance between Syene and Alexandria is 1/50 of the total circumference of Earth. (He assumed they were on the same longitude which isn't quite true.)

A common unit of distance at the time was the *stade*, and Eratosthenes knew the distance between Syene and Alexandria was about 5000 stades. He therefore only needed to multiply 5000 by 50 to get the answer he wanted, 250,000 stades. However, Greek stades and Egyptian stades were slightly different. Was this distance 5000 Greek stades or Egyptian stades?

Using Egyptian stades 5,000 is closer to the actual distance than if we use Greek stades, and also gives a more accurate estimate of the size of our planet so this is probably the unit he used. However, I'll do the calculations using both in the code.

## The Project

This project consists of the following files:

- degree.py
- eratosthenes.py

The files can be downloaded as a zip, or you can clone/download the Github repository if you prefer.

Source Code Links

Replicating Eratosthenes' methods requires some fiddly calculations with angles, specifically latitudes, so I have shifted these out to a separate class called Degree.

In *eratosthenes.py* I use the Degree class to implement the calculations described above.

## The Degree Class

This the Degree class which lives in *degree.py*.

degree.py

class Degree(object):

def __init__(self, degrees = 0, minutes = 0, seconds = 0):

self._seconds = self._seconds_from_dms(degrees, minutes, seconds)

def __str__(self):

dms = self.get()

return f"{dms['degrees']:02d}° {dms['minutes']:02d}′ {dms['seconds']:02d}″"

def set(self, degrees = 0, minutes = 0, seconds = 0):

self._seconds = self._seconds_from_dms(degrees, minutes, seconds)

def get(self):

degrees = self._seconds // 3600

minutes = (self._seconds - (degrees * 3600)) // 60

seconds = self._seconds - (degrees * 3600) - (minutes * 60)

return {"degrees": degrees, "minutes": minutes, "seconds": seconds}

def _seconds_from_dms(self, degrees, minutes, seconds):

return (degrees * 3600) + (minutes * 60) + (seconds)

def fraction_of_circle(self):

return self._seconds / 1_296_000

def set_between(self, deg1, deg2):

if deg1._seconds > deg2._seconds:

self._seconds = deg1._seconds - deg2._seconds

else:

self._seconds = deg2._seconds - deg1._seconds

def to_decimal(self):

degrees = self._seconds // 3600

remaining_seconds = (self._seconds - (degrees * 3600))

decimal_fraction = remaining_seconds / 3600

return degrees + decimal_fraction

## __init__

The class stores an angle in seconds (or to be precise arcseconds, 1/60 of an arcminute) and provides a few handy methods. __init__ takes degrees, minutes and seconds (each defaulting to 0) and calculates and stores self._seconds using a separate function, _seconds_from_dms.

## __str__

Here we get the value as a dictionary with degrees, minutes and seconds, and print these out formated like 31° 12′ 32″. Note that the minute and second symbols aren't ordinary single and double quotes but I have used the prime and double prime symbols borrowed from mathematical notation.

## set

Here we just call _seconds_from_dms, as in __init__. The method isn't used here but might come in handy if you wish to reuse an instance of the class with different values.

## get

This method splits self._seconds into degrees, minutes and seconds, returning the result in a dictionary.

We calculate degrees by floor-dividing (ie // which rounds the result down to the nearest integer) self._seconds by 3600. minutes is calculated in a similar way from the remaining seconds, and finally we calculate seconds from whatever is left over.

## _seconds_from_dms

This is used in __init__ and set, and combines degrees, minutes and seconds into a single seconds value.

## fraction_of_circle

We use this while replicating Eratosthenes' workings, and it calculates the fraction of a circle the current angle represents.

## set_between

This method sets the current angle to the difference between 2 other instances of Degree, and is used in this project to calculate the angle between Alexandria and Syene.

## to_decimal

Units divided into 60 sub-units are a pain for calculations so this function calculates the angle with decimal fractions, for example 07° 12′ 00″ is converted to 7.2 degrees.

## Doing the Calculations

Now we have the Degree class in place we can go ahead and use it to calculate the size of Earth, just as Eratosthenes did over two millenia ago.

eratosthenes.py

import degree

def main():

print("------------------------")

print("| codedrome.com |")

print("| Eratosthenes and the |")

print("| Size of Planet Earth |")

print("------------------------\n")

print("Eratosthenes Values\n-------------------\n")

separation_ancient = degree.Degree(degrees = 7, minutes = 12, seconds = 0)

separation_ancient_decimal = separation_ancient.to_decimal()

distance_stades = 5000

stades_per_degree = distance_stades / separation_ancient_decimal

circumference_stades = stades_per_degree * 360

stades_to_km_Greek = circumference_stades * 0.185

stades_to_km_Egyptian = circumference_stades * 0.1575

print(f"Separation {separation_ancient}\n")

print(f"Separation decimal {separation_ancient_decimal}\n")

print(f"Distance in stades {distance_stades}\n")

print(f"Stades per degree {stades_per_degree:.2f}\n")

print(f"Circumference in stades {circumference_stades}\n")

print(f"Stades to kilometres (Greek) {stades_to_km_Greek}\n")

print(f"Stades to kilometres (Egyptian) {stades_to_km_Egyptian}\n")

print("\nModern Values\n-------------\n")

# Latitude of current Bibliotheca Alexandrina

latitude_Alexandria = degree.Degree(degrees = 31, minutes = 12, seconds = 32)

# Latitude of current Aswan

latitude_Syene = degree.Degree(degrees = 24, minutes = 5, seconds = 20)

separation = degree.Degree()

separation.set_between(latitude_Alexandria, latitude_Syene)

fraction_of_circle = separation.fraction_of_circle()

distance_km = 791.7

circumference_km = distance_km / fraction_of_circle

print(f"Latitude of Alexandria {latitude_Alexandria}\n")

print(f"Latitude of Syene {latitude_Syene}\n")

print(f"Separation {separation}\n")

print(f"Fraction of Circle {fraction_of_circle:.4f}\n")

print(f"Distance in km {distance_km} kilometres\n")

print(f"Circumference {circumference_km:.2f} kilometres\n")

if __name__ == "__main__":

main()

I have actually carried out two separate sets of calculations, firstly with the values and units Eratosthenes would have used and secondly using modern values and units.

The first chunk of code carries out the following steps:

- Create a Degree object with the angle used by Eratosthenes
- Get the decimal equivalent of this value
- Initialise a variable for the distance in stades between the two cities
- Calculate the number of stades per degree
- Calculating the circumference of Earth by multiplying the previous value by 360. (This is apparently how Eratosthenes did it instead of just multiplying the distance by 50.)
- Convert Greek stades to kilometres
- Convert Egyptian stades to kilometres

These values are then printed.

Next let's carry out the calculation in a slightly different way, and using exclusively modern units and values. These are the steps involved.

- Create Degree objects for the latitudes of the two cities
- Create a third Degree object, and call its set_between method to get the angle between the two cities
- Calculate the separation as the angle of a circle
- Hard code the distance between the cities into a variable
- Calculate the circumference of Earth using the distance_km and fraction_of_circle variables

Finally we just print the variables.

## Let's Try it Out

Now we can run the program with this command.

Running the Program

python3 eratosthenes.py

This is the end result.

Program Output

------------------------

| codedrome.com |

| Eratosthenes and the |

| Size of Planet Earth |

------------------------

Eratosthenes Values

-------------------

Separation 07° 12′ 00″

Separation decimal 7.2

Distance in stades 5000

Stades per degree 694.44

Circumference in stades 250000.0

Stades to kilometres (Greek) 46250.0

Stades to kilometres (Egyptian) 39375.0

Modern Values

-------------

Latitude of Alexandria 31° 12′ 32″

Latitude of Syene 24° 05′ 20″

Separation 07° 07′ 12″

Fraction of Circle 0.0198

Distance in km 791.7 kilometres

Circumference 40029.78 kilometres

The currently accepted value for the circumference of Earth is 40,030km. Eratosthenes' value assuming Greek stades is therefore somewhat off at about 15% too high but still pretty good. His Egyptian stades estimate is far better at about 2% too low.