21#include <system_error>
111template<
typename Rep,
typename Precision = std::ratio<1>>
121template<
typename Rep,
typename Precision>
128template<
typename Rep>
129concept not_frequency = !_is_specialization_of_v<Rep, frequency>;
140concept duration_like = _is_specialization_of_v<std::remove_cvref_t<T>, std::chrono::duration>;
153concept distance_like = !duration_like<T> &&
requires(T t) {
163template<
typename Rep>
164struct frequency_values {
166 static constexpr Rep zero() noexcept {
return Rep(0); }
169 static constexpr Rep max() noexcept {
return std::numeric_limits<Rep>::max(); }
172 static constexpr Rep min() noexcept {
return std::numeric_limits<Rep>::lowest(); }
221template<
typename Rep,
typename Precision>
224 static_assert(_is_ratio<Precision>::value,
"precision must be a specialization of std::ratio");
225 static_assert(Precision::num > 0,
"precision must be positive");
246 template<
typename Rep2>
247 requires std::convertible_to<const Rep2&, rep> && (treat_as_inexact_v<rep> || !treat_as_inexact_v<Rep2>)
249 : _r(
static_cast<rep>(r)) {}
264 template<
typename Rep2,
typename Precision2>
265 requires std::convertible_to<const Rep2&, rep> &&
266 detail::_lossless_conversion<Rep2, Precision2, rep, precision> &&
267 detail::_quantity_castable<frequency<Rep2, Precision2>,
frequency>
287 template<
typename Rep2,
typename Precision2>
288 requires(!detail::_lossless_conversion<Rep2, Precision2, rep, precision> ||
289 !std::convertible_to<const Rep2&, rep>) &&
292 : _r(frequency_cast<frequency>(f).
count()) {}
343 requires(!treat_as_inexact_v<rep>)
350 requires(!treat_as_inexact_v<rep>)
396 template<duration_like Duration>
400 using period_ratio = std::ratio_divide<std::ratio<1>,
precision>;
401 using duration_period =
typename Duration::period;
402 using cf = std::ratio_divide<period_ratio, duration_period>;
403 using duration_rep =
typename Duration::rep;
406 return Duration::max();
410 if constexpr (std::is_integral_v<rep> && std::is_integral_v<duration_rep>) {
411 using wider_t = detail::_conversion_integer<rep, duration_rep>;
413 wider_t
count =
static_cast<wider_t
>(_r);
415 if constexpr (cf::den == 1 && cf::num == 1) {
417 return Duration(
static_cast<duration_rep
>(1 /
count));
418 }
else if constexpr (cf::den == 1) {
421 wider_t num =
static_cast<wider_t
>(cf::num);
422 wider_t g = _runtime_gcd(num,
count);
423 wider_t reduced_num = num / g;
424 wider_t reduced_count =
count / g;
425 return Duration(
static_cast<duration_rep
>(reduced_num / reduced_count));
426 }
else if constexpr (cf::num == 1) {
428 wider_t denom =
count *
static_cast<wider_t
>(cf::den);
429 return Duration(
static_cast<duration_rep
>(1 / denom));
433 wider_t num =
static_cast<wider_t
>(cf::num);
434 wider_t g = _runtime_gcd(num,
count);
435 wider_t reduced_num = num / g;
436 wider_t reduced_count =
count / g;
437 wider_t denom = reduced_count *
static_cast<wider_t
>(cf::den);
438 return Duration(
static_cast<duration_rep
>(reduced_num / denom));
442 using cr = std::common_type_t<duration_rep, double>;
444 if constexpr (cf::den == 1 && cf::num == 1) {
445 return Duration(
static_cast<duration_rep
>(1.0 /
static_cast<double>(_r)));
446 }
else if constexpr (cf::den == 1) {
447 return Duration(
static_cast<duration_rep
>(
static_cast<cr
>(cf::num) /
static_cast<double>(_r)));
448 }
else if constexpr (cf::num == 1) {
449 return Duration(
static_cast<duration_rep
>(1.0 / (
static_cast<double>(_r) *
static_cast<cr
>(cf::den))));
452 static_cast<duration_rep
>(
453 static_cast<cr
>(cf::num) / (
static_cast<double>(_r) *
static_cast<cr
>(cf::den))
487 assert(n > 0 &&
"subharmonic divisor must be positive");
514 template<
typename T =
double>
516 double multiplier = std::pow(2.0,
static_cast<double>(octaves));
517 if constexpr (std::is_integral_v<rep>) {
518 return frequency(
static_cast<rep>(std::round(
static_cast<double>(_r) * multiplier)));
520 return frequency(
static_cast<rep>(
static_cast<double>(_r) * multiplier));
548 template<
typename T =
double>
550 double multiplier = std::pow(2.0,
static_cast<double>(semitones) / 12.0);
551 if constexpr (std::is_integral_v<rep>) {
552 return frequency(
static_cast<rep>(std::round(
static_cast<double>(_r) * multiplier)));
554 return frequency(
static_cast<rep>(
static_cast<double>(_r) * multiplier));
569 template<
typename T =
double>
571 return static_cast<T
>(std::log2(
static_cast<double>(_r) /
static_cast<double>(other._r)));
585 template<
typename T =
double>
587 return static_cast<T
>(12.0 * std::log2(
static_cast<double>(_r) /
static_cast<double>(other._r)));
608 template<distance_like Distance, duration_like Duration>
609 constexpr Distance
wavelength(
const Duration& time_per_unit_distance)
const {
611 using period_rep = double;
612 using period_ratio = std::ratio_divide<std::ratio<1>,
precision>;
615 return Distance::max();
619 period_rep wave_period = 1.0 /
static_cast<double>(_r);
622 using duration_period =
typename Duration::period;
623 using time_cf = std::ratio_divide<period_ratio, duration_period>;
624 using time_cr = std::common_type_t<period_rep, typename Duration::rep, double>;
627 time_cr period_in_duration_units;
628 if constexpr (time_cf::den == 1 && time_cf::num == 1) {
629 period_in_duration_units =
static_cast<time_cr
>(wave_period);
630 }
else if constexpr (time_cf::den == 1) {
631 period_in_duration_units =
static_cast<time_cr
>(wave_period) *
static_cast<time_cr
>(time_cf::num);
632 }
else if constexpr (time_cf::num == 1) {
633 period_in_duration_units =
static_cast<time_cr
>(wave_period) /
static_cast<time_cr
>(time_cf::den);
635 period_in_duration_units =
static_cast<time_cr
>(wave_period) *
static_cast<time_cr
>(time_cf::num) /
636 static_cast<time_cr
>(time_cf::den);
640 double wavelength_count = period_in_duration_units /
static_cast<double>(time_per_unit_distance.count());
642 return Distance(
static_cast<typename Distance::rep
>(wavelength_count));
666 template<distance_like Distance>
667 constexpr Distance
wavelength(
double velocity = 299792458.0)
const {
669 return Distance::max();
673 double freq_hz = detail::_ratio_value<precision>(_r);
676 double wavelength_meters = velocity / freq_hz;
680 using distance_period =
typename Distance::period;
681 double wavelength_in_units =
682 wavelength_meters *
static_cast<double>(distance_period::den) /
static_cast<double>(distance_period::num);
684 return Distance(
static_cast<typename Distance::rep
>(wavelength_in_units));
704template<
typename ToFreq,
typename Rep,
typename Precision>
705 requires detail::_quantity_cast_requirements<frequency<Rep, Precision>, ToFreq>
707 return detail::_quantity_cast<ToFreq>(f);
731template<
typename ToFreq,
typename Rep,
typename Precision>
733 return detail::_floor_cast(frequency_cast<ToFreq>(f), f);
757template<
typename ToFreq,
typename Rep,
typename Precision>
759 return detail::_ceil_cast(frequency_cast<ToFreq>(f), f);
779template<
typename ToFreq,
typename Rep,
typename Precision>
781 return frequency_cast<ToFreq>(f);
808template<
typename ToFreq,
typename Rep,
typename Precision>
810 return detail::_round_cast<ToFreq>(f, [&f] {
return floor<ToFreq>(f); });
848template<
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
852 return abs(cf(f1) - cf(f2));
870template<
typename Rep,
typename Precision>
872 return detail::_abs(f);
876template<
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
880 return cf(cf(lhs).count() + cf(rhs).count());
884template<
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
888 return cf(cf(lhs).count() - cf(rhs).count());
892template<
typename Rep1,
typename Precision,
typename Rep2>
893 requires not_frequency<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
897 return cf(cf(f).count() * r);
901template<
typename Rep1,
typename Rep2,
typename Precision>
902 requires not_frequency<Rep1> && std::convertible_to<const Rep1&, std::common_type_t<Rep1, Rep2>>
909template<
typename Rep1,
typename Precision,
typename Rep2>
910 requires not_frequency<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
914 return cf(cf(f).count() / s);
918template<
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
920 -> std::common_type_t<Rep1, Rep2> {
922 return cf(lhs).
count() / cf(rhs).count();
926template<
typename Rep1,
typename Precision,
typename Rep2>
927 requires not_frequency<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>> &&
928 (!treat_as_inexact_v<Rep1> && !treat_as_inexact_v<Rep2>)
932 return cf(cf(f).count() % s);
936template<
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
937 requires(!treat_as_inexact_v<Rep1> && !treat_as_inexact_v<Rep2>)
941 return cf(cf(lhs).count() % cf(rhs).count());
944template<
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
947 return ct(lhs).
count() == ct(rhs).count();
950template<
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
951 requires std::three_way_comparable<std::common_type_t<Rep1, Rep2>>
954 return ct(lhs).
count() <=> ct(rhs).count();
999template<
typename Ratio>
1001 static constexpr const char* value =
nullptr;
1004struct _si_prefix<
std::femto> {
1005 static constexpr const char* value =
"f";
1008struct _si_prefix<
std::pico> {
1009 static constexpr const char* value =
"p";
1012struct _si_prefix<
std::nano> {
1013 static constexpr const char* value =
"n";
1016struct _si_prefix<
std::micro> {
1017 static constexpr const char* value =
"µ";
1020struct _si_prefix<
std::milli> {
1021 static constexpr const char* value =
"m";
1024struct _si_prefix<
std::ratio<1>> {
1025 static constexpr const char* value =
"";
1028struct _si_prefix<
std::kilo> {
1029 static constexpr const char* value =
"k";
1032struct _si_prefix<
std::mega> {
1033 static constexpr const char* value =
"M";
1036struct _si_prefix<
std::giga> {
1037 static constexpr const char* value =
"G";
1040struct _si_prefix<
std::tera> {
1041 static constexpr const char* value =
"T";
1043template<
typename Ratio>
1044inline constexpr const char* _si_prefix_v = _si_prefix<typename Ratio::type>::value;
1055template<
typename Precision>
1056concept _decimal_precision = detail::_power_of_ten_precision<Precision>;
1059template<
typename Rep,
typename Precision>
1060_display _base_unit_display(
const frequency<Rep, Precision>& f) {
1062 return {detail::_ratio_value<p>(f.count()), _si_prefix_v<std::ratio<1>>};
1071template<
typename Rep,
typename Precision>
1072_display _scaled_display(
const frequency<Rep, Precision>& f) {
1076 if constexpr (_decimal_precision<p>) {
1077 x =
static_cast<double>(f.count());
1078 exponent = _precision_exponent<p>;
1080 x = _base_unit_display(f).value;
1083 if (x == 0 || !std::isfinite(x)) {
1084 return {x, _si_prefix_v<std::ratio<1>>};
1087 const detail::_scaled s = detail::_pick_scale(x, exponent, detail::_si_scale);
1088 return {s.value, s.label};
1091#if CONFIG_QUANTA_STD_FORMAT
1094template<
typename Precision>
1095struct _format_traits {
1096 static constexpr const char* markers =
"bs";
1097 static constexpr bool has_own_unit = _si_prefix_v<Precision> !=
nullptr;
1102 static constexpr void no_own_unit_error(
bool fail =
true) {
1104 _format_error(
"frequency: precision has no SI prefix; use an explicit format spec");
1109 static constexpr bool own_unit(
bool power) {
return power; }
1111 template<
typename OutputIt>
1112 static OutputIt append_own_unit(OutputIt out,
bool) {
1113 out = _format_append(out, _si_prefix_v<Precision>);
1114 return _format_append(out,
"Hz");
1117 template<
typename F>
1118 static _display base_display(
const F& f) {
1119 return _base_unit_display(f);
1122 template<
typename F>
1123 static _display scaled_display(
const F& f) {
1124 return _scaled_display(f);
1127 template<
typename OutputIt>
1128 static OutputIt append_label(OutputIt out,
const _display& d) {
1129 out = _format_append(out, d.prefix);
1130 return _format_append(out,
"Hz");
1188template<
typename Rep,
typename Precision>
1191 static_assert(_si_prefix_v<precision> !=
nullptr,
"frequency: precision has no SI prefix");
1192 return _count_string(f.
count()) + _si_prefix_v<precision> +
"Hz";
1204template<
typename Rep,
typename Precision>
1206 const _display d = _base_unit_display(f);
1207 return _fixed_string(d.value) + d.prefix +
"Hz";
1220template<
typename Rep,
typename Precision>
1222 const _display d = _scaled_display(f);
1223 return _fixed_string(d.value) + d.prefix +
"Hz";
1230template<
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
1233 using common_precision = quanta::detail::_common_precision<Precision1, Precision2>;
1239#if CONFIG_QUANTA_STD_FORMAT
1266template<
typename Rep,
typename Precision>
1267struct formatter<
quanta::frequency::frequency<Rep, Precision>>
1268 :
private quanta::detail::_unit_formatter<
1269 quanta::frequency::_format_traits<typename quanta::frequency::frequency<Rep, Precision>::precision>> {
1270 using quanta::detail::_unit_formatter<
1271 quanta::frequency::_format_traits<typename quanta::frequency::frequency<Rep, Precision>::precision>>::parse;
1273 template<
typename FormatContext>
1275 return this->format_quantity(f, ctx);
1286inline namespace literals {
1287inline namespace frequency_literals {
1327namespace frequency {
1328using namespace literals::frequency_literals;
A frequency value with a representation and precision.
constexpr Distance wavelength(const Duration &time_per_unit_distance) const
Calculates the wavelength for this frequency.
constexpr frequency & operator++()
constexpr frequency operator--(int)
typename Precision::type precision
The precision as a std::ratio.
constexpr frequency< typename std::common_type< rep >::type, precision > operator-() const
constexpr rep count() const
Returns the tick count.
constexpr frequency operator++(int)
static constexpr frequency min() noexcept
Returns the minimum representable frequency.
Rep rep
The representation type.
constexpr frequency(const frequency< Rep2, Precision2 > &f)
Explicit constructor for lossy conversions.
static constexpr frequency max() noexcept
Returns the maximum representable frequency.
constexpr frequency & operator*=(const rep &r)
constexpr frequency harmonic(unsigned int n) const
Returns the nth harmonic of this frequency.
frequency octave_shift(T octaves) const
Returns this frequency shifted by a number of octaves.
constexpr frequency()=default
Constructs a zero frequency.
constexpr frequency< typename std::common_type< rep >::type, precision > operator+() const
constexpr Duration period() const
Returns the period of this frequency as a duration.
constexpr frequency(const frequency< Rep2, Precision2 > &f)
Constructs from another frequency with different representation or precision.
T semitones_from(const frequency &other) const
Calculates the interval in semitones between this frequency and another.
constexpr frequency & operator+=(const frequency &f)
frequency semitone_shift(T semitones) const
Returns this frequency shifted by a number of semitones.
constexpr frequency & operator--()
frequency & operator=(const frequency &)=default
constexpr frequency subharmonic(unsigned int n) const
Returns the nth subharmonic of this frequency.
constexpr Distance wavelength(double velocity=299792458.0) const
Calculates the wavelength for this frequency given a propagation velocity.
constexpr frequency & operator%=(const frequency &f)
static constexpr frequency zero() noexcept
Returns a zero frequency.
T octaves_from(const frequency &other) const
Calculates the interval in octaves between this frequency and another.
constexpr frequency & operator/=(const rep &r)
constexpr frequency(const Rep2 &r)
Constructs from a tick count.
constexpr frequency & operator%=(const rep &r)
frequency(const frequency &)=default
constexpr frequency & operator-=(const frequency &f)
Configuration, traits and internals shared by every quanta domain.
quantity< watt_unit, Rep, Precision > power
Power quantity with configurable representation and precision.
frequency< int64_t > hertz
Frequency with 1 Hz precision.
frequency< int64_t, std::kilo > kilohertz
Frequency with 1000 Hz (kilohertz) precision.
frequency< int64_t, std::mega > megahertz
Frequency with 1,000,000 Hz (megahertz) precision.
frequency< int64_t, std::milli > millihertz
Frequency with 0.001 Hz (millihertz) precision.
frequency< int64_t, std::giga > gigahertz
Frequency with 1,000,000,000 Hz (gigahertz) precision.
frequency< int64_t, std::tera > terahertz
Frequency with 1,000,000,000,000 Hz (terahertz) precision.
Frequency types and utilities.
constexpr ToFreq trunc(const frequency< Rep, Precision > &f)
Converts a frequency to the target type, rounding toward zero.
constexpr bool is_frequency_v
constexpr auto operator+(const frequency< Rep1, Precision1 > &lhs, const frequency< Rep2, Precision2 > &rhs) -> std::common_type_t< frequency< Rep1, Precision1 >, frequency< Rep2, Precision2 > >
Returns the sum of two frequencies.
constexpr auto operator-(const frequency< Rep1, Precision1 > &lhs, const frequency< Rep2, Precision2 > &rhs) -> std::common_type_t< frequency< Rep1, Precision1 >, frequency< Rep2, Precision2 > >
Returns the difference of two frequencies.
constexpr ToFreq round(const frequency< Rep, Precision > &f)
Converts a frequency to the target type, rounding to nearest (ties to even).
constexpr auto operator/(const frequency< Rep1, Precision > &f, const Rep2 &s) -> frequency< std::common_type_t< Rep1, Rep2 >, Precision >
Divides a frequency by a scalar.
constexpr ToFreq floor(const frequency< Rep, Precision > &f)
Converts a frequency to the target type, rounding toward negative infinity.
constexpr auto operator<=>(const frequency< Rep1, Precision1 > &lhs, const frequency< Rep2, Precision2 > &rhs)
constexpr bool operator==(const frequency< Rep1, Precision1 > &lhs, const frequency< Rep2, Precision2 > &rhs)
constexpr ToFreq ceil(const frequency< Rep, Precision > &f)
Converts a frequency to the target type, rounding toward positive infinity.
constexpr frequency< Rep, Precision > abs(const frequency< Rep, Precision > &f)
Returns the absolute value of a frequency.
std::string to_string(const frequency< Rep, Precision > &f)
Converts a frequency to a string with its precision-qualified unit.
constexpr auto beat(const frequency< Rep1, Precision1 > &f1, const frequency< Rep2, Precision2 > &f2) -> std::common_type_t< frequency< Rep1, Precision1 >, frequency< Rep2, Precision2 > >
Calculates the beat frequency between two frequencies.
constexpr auto operator*(const frequency< Rep1, Precision > &f, const Rep2 &r) -> frequency< std::common_type_t< Rep1, Rep2 >, Precision >
Multiplies a frequency by a scalar.
constexpr ToFreq frequency_cast(const frequency< Rep, Precision > &f)
Converts a frequency to a different precision or representation.
Type-safe units modeled after std::chrono.
constexpr scaled_t scaled
Selects the scaled form in to_string().
constexpr base_unit_t base_unit
Selects the base-unit form in to_string().
constexpr bool treat_as_inexact_v
Tag type selecting the base-unit form, see base_unit.
Trait to detect frequency specializations.
Tag type selecting the scaled form, see scaled.
Trait to indicate floating-point-like behavior.