tb-formula

The tb-formula directive creates a calculated numeric question. Authors define variable ranges, use variable placeholders in the question, and provide one formula that computes the expected answer from the generated values.

Synopsis

The general format of the tb-formula directive is:

.. tb-formula::
   :variables: x=min..max, y=min..max
   :optional parameter: value

   + --- Question area ---
   |
   | question text with {{x}} and {{y}} placeholders
   |
   + --- Answer formula ---

   .. answer-formula:: javascript

      formula using the variables

Options

variables

String. Required. Comma-separated or semicolon-separated variable ranges. Each range uses name=min..max syntax. If both endpoints are integers, HTML generates integer values. Decimal endpoints generate decimal values.

class

String or List. Optional. A CSS class to add to the directive. See Common options for details.

name

String. Optional. Sphinx reference name for this calculated formula question. See Common options for details.

tolerance

Number. Optional. Accepted absolute difference from a numeric formula result. The default is 0. If the formula returns a range, tolerance is not used.

Sphinx configuration options

tb_formula_default_endpoint

String. Optional. URL for remote formula execution when answer-formula uses a language other than javascript or js. The default is the same JOBE runs endpoint used by tb-code.

tb_formula_language_defaults

Dictionary. Optional. Default JOBE parameters for remote formula languages. Supported keys are compileargs, linkargs, runargs, and interpreterargs.

Answer formula

The nested answer-formula block accepts an optional language argument. When omitted, the language is javascript.

JavaScript formulas run in the browser and can refer to each variable by name. Other languages are sent to a remote server execution endpoint. tb-formula sends the generated variables as JSON text on standard input. Results should print to standard output.

Remote formula blocks can set JOBE parameters with :compileargs:, :linkargs:, :runargs:, and :interpreterargs: options. These options accept either a shell-style string or a Python-style list of strings.

A formula can return:

  • a number, such as 4 * y + 3 * x

  • a range of acceptable values as either:

    • a two-item range as a JSON array, such as [359, 361]

    • a JSON object with min and max keys

Accessibility behavior

HTML shows the generated values as text and uses a text input with decimal keyboard hints for the answer. The Check answer and New values controls are native buttons. Result text uses a status region so assistive technology can announce feedback.

Fallback behavior

HTML without JavaScript shows the question with placeholder blanks and an answer input. Text and PDF-oriented builders render the question with one deterministic value for each generated variable and a blank answer area. The static value is the midpoint of the configured range, rounded for integer ranges. Static output does not include the formula.

Examples

Example 1: Glasses of water

Source

.. tb-formula::
   :variables: x=4..8, y=10..20

   If a small glass can hold {{x}} ounces of water, and a large
   glass can hold {{y}} ounces of water, what's the total number of
   ounces in 4 large and 3 small glasses of water?

   .. answer-formula:: javascript

      4 * y + 3 * x

Rendered

If a small glass can hold {{x}} ounces of water, and a large glass can hold {{y}} ounces of water, what’s the total number of ounces in 4 large and 3 small glasses of water?

Example 2: Tolerance

Source

.. tb-formula::
   :variables: radius=2.0..5.0
   :tolerance: 0.05

   A circle has radius {{radius}}. What is its area?

   .. answer-formula:: javascript

      Math.PI * radius * radius

Rendered

A circle has radius {{radius}}. What is its area?

Example 3: Fixed answer range

Source

.. tb-formula::
   :variables: width=10..20

   A board is {{width}} centimeters wide. Estimate its width to the
   nearest 5 centimeters.

   .. answer-formula:: javascript

      [width - 2.5, width + 2.5]

Rendered

A board is {{width}} centimeters wide. Estimate its width to the nearest 5 centimeters.

Example 4: Data-dependent range

Source

.. tb-formula::
   :variables: distance=80..120, time=8..12

   A cart travels {{distance}} meters in {{time}} seconds. What is
   its speed in meters per second? Answers within 5 percent are
   accepted.

   .. answer-formula:: javascript

      ({ min: (distance / time) * 0.95, max: (distance / time) * 1.05 })

Rendered

A cart travels {{distance}} meters in {{time}} seconds. What is its speed in meters per second? Answers within 5 percent are accepted.

Example 5: Remote formula program

Source

.. tb-formula::
   :variables: x=1..10, y=1..10

   What is {{x}} plus {{y}}?

   .. answer-formula:: python3

      import json
      import sys

      values = json.load(sys.stdin)
      print(values["x"] + values["y"])

Rendered

What is {{x}} plus {{y}}?

Example 6: Minimal C++ formula program

Source

.. tb-formula::
   :variables: n=2..9

   What is {{n}} squared?

   .. answer-formula:: cpp
      :compileargs: ['-std=c++11']

      #include <cctype>
      #include <iostream>
      #include <iterator>
      #include <string>

      int main() {
        std::string input(
          (std::istreambuf_iterator<char>(std::cin)),
          std::istreambuf_iterator<char>()
        );
        std::string digits;
        for (char c : input) {
          if (std::isdigit(static_cast<unsigned char>(c))) {
            digits += c;
          }
        }
        int n = std::stoi(digits);
        std::cout << n * n << '\n';
        return 0;
      }

Rendered

What is {{n}} squared?