Skip to content

Working with Temperatures

Temperature conversions are one of the most error-prone areas in scientific and engineering calculations. The distinction between temperature points (absolute values) and temperature differences (deltas) is crucial but often overlooked, leading to subtle bugs that can have serious real-world consequences.

This workshop will teach you how to use mp-units to handle temperature calculations correctly and safely, preventing common conversion errors that plague many codebases.

Problem statement

For example, the difference between 20 °C (68 °F) and 10 °C (50 °F) is 10 °C (18 °F). However, if you incorrectly apply the point conversion formula to the difference (10 °C × 9/5 + 32 = 50 °F), you get the wrong answer!

The key insight is that temperature differences only need scaling (×9/5 for C→F), while temperature points additionally require an offset (+32 for C→F).

Your task

The weather forecast in Europe

Today there is 19 ℃ outside. Tomorrow we can expect increase to 21 ℃. Unfortunately, a cold front is approaching so in the following days the temperature will drop by 5 ℃.

A US citizen listening to this forecast wants to convert those temperatures to degree Fahrenheit. Please help him with this task:

  1. Express both temperature points (today and tomorrow) in ℉.
  2. Find out how much warmer it will be tomorrow (temperature difference in both ℃ and ℉).
  3. Calculate the temperature that is forecasted for the rest of the week (after the 5 ℃ drop).

Challenge: Refactor the code below from using raw doubles and unsafe macros to mp-units strong types that prevent temperature conversion errors.

// ce-embed height=650 compiler=clang2110 flags="-std=c++23 -stdlib=libc++ -O3" mp-units=trunk
#include <mp-units/systems/si.h>
#include <mp-units/systems/usc.h>
#include <iostream>

using namespace mp_units;
using namespace mp_units::si::unit_symbols;
using namespace mp_units::usc::unit_symbols;

#define POINT_C_TO_F(temp) ((temp) * 9.0 / 5.0 + 32.0)
#define DELTA_C_TO_F(temp) ((temp) * 9.0 / 5.0)

void print_temp(std::string_view title, double t)
{
  std::cout << title << ": " << t << " (" << POINT_C_TO_F(t) << ")\n";
}

int main()
{
  double today_pt_C = 19;
  double tomorrow_pt_C = 21;
  double diff_C = tomorrow_pt_C - today_pt_C;
  double later_pt_C = tomorrow_pt_C - 5;

  std::cout << "Today: " << today_pt_C << " ℃ (" << POINT_C_TO_F(today_pt_C) << " ℉)\n";
  std::cout << "Tomorrow: " << tomorrow_pt_C << " ℃ (" << POINT_C_TO_F(tomorrow_pt_C) << " ℉)\n";
  std::cout << "Diff: " << diff_C << " ℃ (" << DELTA_C_TO_F(diff_C) << " ℉)\n";
  std::cout << "Later: " << later_pt_C << " ℃ (" << POINT_C_TO_F(later_pt_C) << " ℉)\n";
}
Solution
#include <mp-units/systems/si.h>
#include <mp-units/systems/usc.h>
#include <iostream>

using namespace mp_units;
using namespace mp_units::si::unit_symbols;
using namespace mp_units::usc::unit_symbols;

void print_temp(std::string_view title, Quantity auto t)
{
  std::cout << title << ": " << t << " (" << t.in(deg_F) << ")\n";
}

void print_temp(std::string_view title, QuantityPoint auto t)
{
  std::cout << title << ": " << t.quantity_from_zero() << " (" << t.in(deg_F).quantity_from_zero() << ")\n";
}

int main()
{
  quantity_point today = point<deg_C>(19.);
  quantity_point tomorrow = point<deg_C>(21.);
  quantity diff = tomorrow - today;
  quantity_point later = tomorrow - delta<deg_C>(5.);

  print_temp("Today", today);
  print_temp("Tomorrow", tomorrow);
  print_temp("Diff", diff);
  print_temp("Later", later);
}
What you learned?

Temperature points vs. deltas

Temperatures require two distinct types:

quantity_point today = point<deg_C>(19.);     // Absolute temperature
quantity diff = delta<deg_C>(5.);             // Temperature difference
  • Points (quantity_point): Absolute temperatures ("19 °C")
  • Deltas (quantity): Temperature differences ("5 °C warmer")
  • You cannot add two points, but you can add a delta to a point

Different conversion formulas

The key insight: absolute and relative temperatures convert differently:

// Converting a point: 0°C = 32°F  (different zeros!)
point<deg_C>(0.)  point<deg_F>(32.)

// Converting a delta: 1°C difference = 1.8°F difference
delta<deg_C>(1.)  delta<deg_F>(1.8)
  • Points account for offset between zero points
  • Deltas only scale by the ratio between units
  • mp-units applies the correct formula automatically

Type-safe temperature operations

The type system prevents common errors:

quantity_point - quantity_point  quantity     // ✅ Difference between temps
quantity_point + quantity  quantity_point     // ✅ Adding a delta to a point
quantity_point + quantity_point  ERROR        // ❌ Can't add two absolute temps

Extracting deltas from the origin

The .quantity_from_zero() method gives you the delta from the unit's point origin:

quantity_point temp = point<deg_C>(20.);
quantity delta_from_origin = temp.quantity_from_zero();  // 20 °C from 0 °C
  • For units with defined point origins (like °C, °F, K), returns the delta from that origin (0 °C, 0 °F, or 0 K)
  • For quantities with explicitly defined absolute point origins (like altitude from mean sea level), returns the delta from that absolute origin
  • Useful when you need to express a temperature point as a difference from its scale's reference

References

Takeaways

  • Temperature points vs. deltas: Absolute temperatures and temperature differences require different conversion formulas
  • Type safety: mp-units prevents common temperature conversion errors at compile time
  • Automatic conversions: The .in() method handles proper unit conversions automatically
  • Getting deltas from points: .quantity_from_zero() allows us to get a delta for a temperature point from 0 degrees in the current temperature system
  • Overloaded functions: Use function overloading to handle different quantity types elegantly
  • Real-world safety: Strong typing prevents bugs that could occur in critical applications like weather systems or industrial processes