Skip to main content

MTH229 with Julia

Author

CSI Math department

Published

November 7, 2026

Preface

Introduction

MTH229 at the College of Staten Island is a course to introduce a programming language to reinforce concepts of a first-semester calculus course from numerical and graphical points of view.

Some sections use the Julia programming language. For Julia, the computer-lab “projects” are on WeBWorK and there should be sufficient background material therein to work through the details. In the notes here can be found additional detail for those seeking it. For a more thorough introduction, visit Calculus with Julia.

Installation details for Julia are at the end of this page, but most students will use a departmental web server to access Julia.

These notes are broken into different sections, where most all sections have some self-grading questions at the end that allow you to test your knowledge of that material. The code should be copy-and-pasteable into a Julia session. The code output is similar to what would be shown if evaluated in an IJulia cell, our recommended interface while learning Julia (though some may like the Pluto interface as well).

The notes mostly follow topics of a standard first-semester calculus course after some background material is presented for learning Julia within a mathematical framework.

Each topic has a lab project. At CSI, sufficient time is allotted to complete these projects during the lab class. These projects are available as IJulia notebooks. (The Pluto notebooks are also available, though those haven’t been updated in a while. These have recordings with 5-10 minutes of commentary, should that prove interesting.) Find links for these near the top of each page of notes.

For example, blank notebooks for test taking, etc. are found by following these links:

ipynb

Lab notebook

A laboratory notebook is a useful tool for keeping notes. One specific for this class is available for printing out: LabNotebook

WeBWorK

Most background material, and the questions are now presented and completed through WeBWorK.

The provided .ipynb notebooks only contain modest background details and a few examples.

Each WeBWorK page has an introduction to some part of the material and a series of questions and comments related to the introduction.

There are a few idiosyncrasies in the WeBWorK pages to be aware of:

Typesetting of code examples

The code examples may be typeset in WeBWorK as though they appear in a terminal. The terminal formatting (or REPL, read-evaluate-print-loop) is indicated with a leading prompt julia>. Interacting with terminal is interactive: a command is read in, evaluated, its output is printed. The output displayed directly below the command which is prefixed with the prompt.

This is in contrast to some examples where a block of code is typeset as though it were the input for a notebook cell. Notebooks take a block of input, evaluate the block, and then print out the last command that was executed. (The use of @show or print(...) can be used to display intermediate values in a cell.) Notebooks are how you are expected to interact with Julia.

Comments in code

The pound sign (#) in Julia instructs the interpreter that everything afterwards on the line is a comment. While the Julia interpreter can ignore what comes after the pound sign, it is expected that the human interpreter gets some additional bit of detail about why the command is as it is.

Typesetting of math

WeBWorK allows the use of MathJax, a JavaScript display engine, for mathematics giving math a distinct look. In contrast, code is typeset using a typewriter style, fixed width font.

Copy and paste from a WeBWorK page

Copying and pasting from WeBWorK into a notebook will usually be unsuccessful as the interesting parts are typeset with MathJax. For the intrepid, the rendered text can be selected by using “right-click” (or “control-click” on a mac) and the “Copy to Clipboard” with “TeX Commands”. Some editing will be necessary.

Numeric answers

For most questions with a numeric answer it is best to copy all 16 digits of output. Several digits are expected to match a correct answer. For numeric questions where an estimate is made, say from a graph, this is significantly relaxed.

Scientific notation

While Julia is very happy to express its output using scientific notation, WeBWorK is not happy to receive the exact output for an answer. Either replace e with E (as in 1.23e4 would be 1.23E4) or use decimals.

Lists of numbers

Many questions expect one or more answers. Separating each one with a comma is needed for WeBWorK to distinguish the different answers.

Other answers

If the answer is to be a function, the automatic grader is expecting just the rule of the function (an expression), as in for f(x) = sin(x) just enter sin(x).

Using Julia in MTH229

Interacting with Julia

There are many ways one can “run” Julia, but the primary one for MTH229 is to use the department’s “juliabox” server.

The server uses a notebook interface to Julia. The notebook is Jupyter, which is used with other programming languages, and implements many conventions. Basic usage becomes straightforward, but there are some subtler details:

  • A notebook consists of cells where the user enters one or more commands (new commands are separated by newlines or semi-colons). It is suggested to use multiple commands in a single cell if they related to the same problem, as this makes editing much easier.
  • Cells are run by clicking a “run” button or by a keyboard shortcut, like shift-enter.
  • the output of the last command executed in a cell is displayed below the cell. This output may be empty, a graphic, a number, a bunch of numbers … Values may be copy-and-pasted into WeBWorK.
  • multiple outputs can be shown using a comma to separate calls
  • Once a cell is called it gets an execution number assigned to it. These indicate the order of evaluation. As values can be modified or updated, it is important to keep track of what was evaluated when. (It is by number, not by location in the notebook).
  • Packages to add external features need to be loaded only once in a session.
  • A session sometimes (not often) can get interrupted. They can usually be restarted by restarting the kernel through a menu option.
  • There may be one or more notebooks open at a time. Open notebooks tie up limited memory resources so having too many open can be problematic. (At the moment no more than 3 is recommended. Too many notebooks open is a common reason why sessions need to restarted.)
  • different notebooks do not share values.
  • The notebook is typically saved to be used in new sessions, but each time it must be reloaded. Saving is a nice feature, but may fail for technical reasons. To be sure of no data loss, download the notebook as an ipynb file.

Basic ideas

Julia makes an excellent choice as a computer supplement for this material as its syntax is very similar to standard mathematical syntax. The ability to define mathematical functions using the familiar f(x) = ... notation makes getting started really easy. Further, the fact that functions are first-class objects means that it is possible to create higher-order Julia functions that mirror the standard operations of calculus. The following pattern is used throughout:

action(function_object, args...)

For example, the notes use:

  • plot(f, a, b) to plot f over [a,b]; plot!(g) to add a curve (using Plots)
  • fzero(f, (a, b)) or fzero(f, a, b) to find a zero between the bracketing interval [a,b] (from Roots)
  • fzero(f, a) (or fzero(f, a)) to find a zero near an initial starting point a (from Roots)
  • lim(f, c) to numerically investigate the limit of f at x=c.
  • limit(f(x), x=>c) to find the limit of f at c (from SymPy)
  • f' to return a function that computes the derivative of f (Added in the MTH229 package based on the derivative function from the ForwardDiff package)
  • diff(f(x),x) to find a symbolic derivative of f (from SymPy)
  • fzeros(f, (a, b)) (or fzeros(f, a,b)) to find all the real zeros of a function f in [a,b] (from Roots)
  • sign_chart(f, a, b) to find and classify zeros of a function over [a,b]
  • quadgk(f, a, b) to find the numeric integral of f over (a,b) (from the QuadGK package)
  • integrate(f(x), x) to find the symbolic integral of f (from the SymPy package)
  • integrate(f(x), (x, a, b)) to find the definite integral over [a,b] symbolically (from the SymPy package).

With just this basic set of actions, akin to buttons on the calculator, a rich variety of problems can be addressed.

Help and errors

Most functions in Julia are documented. To access the documentation we issue the command prefixed with a question mark, as in ?sin. At the REPL, typing a leading ? turns on the help mode. In Jupyter, the query should be the only thing in the cell.

Help can be narrowed to respond to just certain argument types.

Errors

There are a variety of common errors encountered when first interacting with Julia. We try to enumerate them here.

Parsing errors

  • ERROR: MethodError: no method matching ^(::typeof(sin), ::Int64): This error is thrown when trying to execute sin^2(3). The issue is there is no means to square the function object, rather we square the value of the function after calling it on 3: sin(3)^2

  • ERROR: ParseError:...space required before '?' operator This came when trying to use the ternary operator without spaces around the ? and : (by typing x<1?2:3 and not x<1 ? 2 : 3).

  • ERROR: ParseError:...whitespace is not allowed here The error came by including a space after the function name and before the opening parentheses when calling the function. That is sin (3) errors, sin(3) does not.

  • ParseError:...Expected ')' This came because a non-matching number of parentheses was used – fewer closing than opening. The explanatory message will be extra tokens after end of expression if there are more closing than opening.

Incorrect function usage

  • ERROR: DomainError with -1.0: This happened when putting a negative (real) number into the log function, in particular entering log(-1). A similar error will happen with sqrt(-1) and with sin(Inf), though each has particular clarifying language.

  • ERROR: MethodError: objects of type Float64 are not callable This occurs when there is a missing multiplication sign. For example the expression (sin(3))(sin(4)) will error, as it sees the parentheses around sin(4) as a function call. However, such notation does work with numeric literals, so it can be confusing. We recommend using * when you mean multiply.

Technical errors

  • ERROR: cannot define function h; it already has a value. Julia has two types of functions: anonymous and generic. Generic functions are what we mostly model in this class. They are called generic as each function can have many different implementations (methods). To make this work, a lookup-table is used to store the function name and the number and type of arguments the method is defined for. To do this, once a generic function is defined, it can’t be repurposed as a different variable. Similarly, if you use a name as a variable (eg. h=2) it can no longer be used as a generic function name (eg. h(x) = sin(x)). We recommend sticking to familiar math names for variables (e.g. x, y), familiar names for parameters, (a, b, m, …), and familiar math names for functions (e.g., f, g, …). This works pretty well, but sometimes there is crossover, such as with h.

Oops and not an error

It is possible to redefine and shadow basic math operations. For example, if you were to type the following equation into Julia:

x + y = 3

you will not get an equation, rather this will redefine the addition of two variables, always returning 3. Oops. Often redefinition causes and error, such as entering this equation

sin(x) = 3   # ERROR: invalid method definition in Main: function Base.sin must be explicitly imported to be extended

To break out of this is tough, you need to redefine +, reaching into Base.:+ to do so

x + y = Base.:+(x,y)

We recommend learning fast that equations are not entered directly into Julia.

Installing Julia on a personal laptop or computer.

Installing Julia is not terribly difficult, but does involve a few additional steps. Use juliaup to manage a Julia installation

On Windows from the command line run

winget install julia -s msstore

On Mac or Linux, from the command line run

curl -fsSL https://install.julialang.org | sh

These two command install juliaup, which you then run from the command line to install Julia.

Details on additional packages to install for MTH229 are listed at https://github.com/mth229/MTH229.jl/.

Using Julia for free online

In a pinch, there are online instances (resource-constrained) that can be used:

  • Colab. Google’s colab service allows the free user more computing power than does binder but does require more setup. This is working as of March 2025:

Go to google colab:

https://colab.research.google.com/

Click on “Runtime” menu and then “Change Runtime Type”

Select Julia as the “Runtime Type” then save

Copy and paste then run this set of commands

using Pkg
Pkg.add("Plots")
Pkg.add("MTH229")
using MTH229
using Plots

This may take 2-3 minutes to load. The plotly() backend doesn’t work out of the box. Use gr() to recover if that command is issued.

  • Binder. Binder is a free service for small images though it can be very temperamental. Binder has an inactivity time out of a few minutes. Two images are available, the one without SymPy loads much faster and would typically suffice, though has no symbolic capabilities.

Run on Binder Run on binder (with SymPy)

Run on Binder w/o SymPy Run on binder (without SymPy)


This table covers pros and cons for the approaches mentioned above:

                         Using server    Colab   Binder  Local Installation
Setup ease                  ✓              ~       ✓          ×

Speed                       ✓              ✓       ×          ✓

Persistence of work         ×              ✓       ×          ✓

Free                        ✓              ✓       ✓          ✓

Use at home                 ✓              ✓       ✓          ✓