cyberangles blog

Ratio Manipulations in C++ | Set 2 (Comparison)

In the previous installment of our series on ratio manipulations in C++, we explored the basic concepts and operations related to ratios. In this blog post, we will delve into the comparison of ratios in C++. Comparing ratios is a fundamental operation that allows us to determine the relative magnitudes of different ratios. This is crucial in various applications, such as in numerical calculations, handling units of measurement, and dealing with fractions. C++ provides a powerful and efficient way to perform ratio comparisons through its <ratio> library. In this article, we will cover the different comparison operators available for ratios, how to use them, and some best practices when working with ratio comparisons.

2026-07

Table of Contents#

  1. Understanding Ratios in C++
  2. Comparison Operators for Ratios
  3. Example Usage
  4. Common Practices
  5. Best Practices
  6. Conclusion
  7. References

1. Understanding Ratios in C++#

Before we dive into the comparison of ratios, let's briefly recap what ratios are in C++. The <ratio> library in C++ provides a compile - time ratio representation. A ratio is defined by two integers: a numerator and a denominator. For example, if we want to represent the ratio 3/4 in C++, we can use the std::ratio template as follows:

#include <iostream>
#include <ratio>
 
int main() {
    using three_fourths = std::ratio<3, 4>;
    std::cout << three_fourths::num << "/" << three_fourths::den << std::endl;
    return 0;
}

In this code, std::ratio<3, 4> defines a ratio with a numerator of 3 and a denominator of 4. The num and den member constants of the std::ratio type represent the numerator and denominator respectively.

2. Comparison Operators for Ratios#

The <ratio> library in C++ provides several comparison operators to compare two ratios. These operators are templates that take two std::ratio types as parameters.

2.1 std::ratio_equal#

The std::ratio_equal template checks if two ratios are equal. It returns a std::true_type if the ratios are equal and a std::false_type otherwise.

#include <iostream>
#include <ratio>
 
int main() {
    using r1 = std::ratio<1, 2>;
    using r2 = std::ratio<2, 4>;
    using r3 = std::ratio<1, 3>;
 
    std::cout << std::boolalpha;
    std::cout << std::ratio_equal<r1, r2>::value << std::endl; // true
    std::cout << std::ratio_equal<r1, r3>::value << std::endl; // false
    return 0;
}

In this example, std::ratio_equal<r1, r2>::value is true because the ratios 1/2 and 2/4 are equivalent. Meanwhile, std::ratio_equal<r1, r3>::value is false as 1/2 and 1/3 are not equal.

2.2 std::ratio_not_equal#

The std::ratio_not_equal template is the opposite of std::ratio_equal. It checks if two ratios are not equal. It returns a std::true_type if the ratios are not equal and a std::false_type if they are equal.

#include <iostream>
#include <ratio>
 
int main() {
    using r1 = std::ratio<1, 2>;
    using r2 = std::ratio<2, 4>;
    using r3 = std::ratio<1, 3>;
 
    std::cout << std::boolalpha;
    std::cout << std::ratio_not_equal<r1, r2>::value << std::endl; // false
    std::cout << std::ratio_not_equal<r1, r3>::value << std::endl; // true
    return 0;
}

2.3 std::ratio_less#

The std::ratio_less template checks if the first ratio is less than the second ratio. It returns a std::true_type if the first ratio is less than the second ratio, and a std::false_type otherwise.

#include <iostream>
#include <ratio>
 
int main() {
    using r1 = std::ratio<1, 2>;
    using r2 = std::ratio<2, 3>;
 
    std::cout << std::boolalpha;
    std::cout << std::ratio_less<r1, r2>::value << std::endl; // true
    return 0;
}

Here, 1/2 is less than 2/3, so std::ratio_less<r1, r2>::value is true.

2.4 std::ratio_less_equal#

The std::ratio_less_equal template checks if the first ratio is less than or equal to the second ratio. It returns a std::true_type if the condition is met, and a std::false_type otherwise.

#include <iostream>
#include <ratio>
 
int main() {
    using r1 = std::ratio<1, 2>;
    using r2 = std::ratio<2, 4>;
    using r3 = std::ratio<2, 3>;
 
    std::cout << std::boolalpha;
    std::cout << std::ratio_less_equal<r1, r2>::value << std::endl; // true
    std::cout << std::ratio_less_equal<r1, r3>::value << std::endl; // true
    return 0;
}

2.5 std::ratio_greater#

The std::ratio_greater template checks if the first ratio is greater than the second ratio. It returns a std::true_type if the condition is met, and a std::false_type otherwise.

#include <iostream>
#include <ratio>
 
int main() {
    using r1 = std::ratio<2, 3>;
    using r2 = std::ratio<1, 2>;
 
    std::cout << std::boolalpha;
    std::cout << std::ratio_greater<r1, r2>::value << std::endl; // true
    return 0;
}

2.6 std::ratio_greater_equal#

The std::ratio_greater_equal template checks if the first ratio is greater than or equal to the second ratio. It returns a std::true_type if the condition is met, and a std::false_type otherwise.

#include <iostream>
#include <ratio>
 
int main() {
    using r1 = std::ratio<2, 3>;
    using r2 = std::ratio<1, 2>;
    using r3 = std::ratio<4, 6>;
 
    std::cout << std::boolalpha;
    std::cout << std::ratio_greater_equal<r1, r2>::value << std::endl; // true
    std::cout << std::ratio_greater_equal<r1, r3>::value << std::endl; // true
    return 0;
}

3. Example Usage#

Let's consider an example where we have a list of ratios and we want to find the smallest ratio.

#include <iostream>
#include <ratio>
#include <type_traits>
 
template<typename R1, typename R2>
using smaller_ratio = std::conditional<std::ratio_less<R1, R2>::value, R1, R2>;
 
template<typename... Ratios> struct smallest_ratio;
 
template<typename R, typename... Ratios>
struct smallest_ratio<R, Ratios...> {
    using type = typename smaller_ratio<R, typename smallest_ratio<Ratios...>::type>::type;
};
 
template<typename R>
struct smallest_ratio<R> {
    using type = R;
};
 
int main() {
    using r1 = std::ratio<1, 2>;
    using r2 = std::ratio<2, 5>;
    using r3 = std::ratio<3, 7>;
 
    using smallest = typename smallest_ratio<r1, r2, r3>::type;
    std::cout << smallest::num << "/" << smallest::den << std::endl;
    return 0;
}

In this example, we define a smaller_ratio alias template that selects the smaller of two ratios. Then, we define a smallest_ratio struct template that recursively finds the smallest ratio among a list of ratios.

4. Common Practices#

  • Use Compile - Time Ratios: Since ratio comparisons in C++ are done at compile - time, it is best to use these techniques when the ratios are known at compile - time. This can lead to more efficient code as the compiler can optimize the comparisons.
  • Handle Negative Ratios Properly: The <ratio> library can handle negative ratios. Make sure to understand how the comparison operators work with negative ratios. For example, a negative ratio is considered less than a positive ratio.

5. Best Practices#

  • Keep Ratios Simplified: The <ratio> library automatically simplifies ratios. This helps in accurate comparisons. Avoid manually modifying the numerator and denominator in a way that could lead to non - simplified ratios.
  • Use Type Aliases: When working with multiple ratios, use type aliases to make the code more readable. For example, instead of writing std::ratio<3, 4> multiple times, use a type alias like using three_fourths = std::ratio<3, 4>.

6. Conclusion#

In this blog post, we have explored the comparison of ratios in C++. The <ratio> library provides a set of powerful comparison operators that allow us to compare ratios at compile - time. We have seen how to use std::ratio_equal, std::ratio_not_equal, std::ratio_less, and other comparison templates. By following the common and best practices, we can write efficient and readable code when dealing with ratio comparisons.

7. References#