Loading CMakeLists.txt +1 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ # cmake_minimum_required (VERSION 3.14) project (cppduals VERSION 0.6.1 VERSION 0.6.2 LANGUAGES C CXX ) include (GNUInstallDirs) Loading duals/dual +134 −71 Original line number Diff line number Diff line Loading @@ -861,6 +861,8 @@ namespace detail { template<class T> bool isnan_impl(const dual<T> & x); template<class T> bool signbit_impl(const dual<T> & x); template<class T> dual<T> copysign_impl(const dual<T> & x, const dual<T> & y); template<class T> dual<T> log1p_impl(const dual<T> & x); template<class T> dual<T> expm1_impl(const dual<T> & x); template<class T> dual<T> random_impl(const dual<T> & low, const dual<T> & high); template<class T> dual<T> random2_impl(const dual<T> & low, const dual<T> & high); } Loading Loading @@ -942,8 +944,8 @@ template <typename T> int sgn(T val) { } } template<class T> dual<T> log1p(const dual<T> & x); template<class T> dual<T> expm1(const dual<T> & x); template<class T> dual<T> log1p(const dual<T> & x) {return detail::log1p_impl(x);} template<class T> dual<T> expm1(const dual<T> & x) {return detail::expm1_impl(x);} #if __cpp_user_defined_literals >= 200809 /// Dual number literals in namespace duals::literals Loading Loading @@ -1371,22 +1373,67 @@ atan2_scalar_dual(const U & y, const dual<T> & x) { } template<class T> duals::dual<T> hypot_impl(const duals::dual<T> & x, const duals::dual<T> & y) { return sqrt(x*x + y*y); using std::hypot; return dual<T>(hypot(x.rpart(), y.rpart()), (x.rpart() * y.dpart() + y.rpart() * x.dpart()) / hypot(x.rpart(), y.rpart())); } template<class T> duals::dual<T> scalbn_impl(const duals::dual<T> & arg, int ex) { return arg * std::pow((T)2, ex); } template<class T> dual<T> sinh(const dual<T> & x); template<class T> dual<T> cosh(const dual<T> & x); template<class T> dual<T> tanh(const dual<T> & x); template<class T> dual<T> asinh(const dual<T> & x); template<class T> dual<T> acosh(const dual<T> & x); template<class T> dual<T> atanh(const dual<T> & x); template<class T> dual<T> sinh_impl(const dual<T> & x) { using std::sinh; using std::cosh; return dual<T>(sinh(x.rpart()), x.dpart() * cosh(x.rpart())); } template<class T> dual<T> cosh_impl(const dual<T> & x) { using std::cosh; using std::sinh; return dual<T>(cosh(x.rpart()), x.dpart() * sinh(x.rpart())); } //template<class T> dual<T> log1p(const dual<T> & x); //template<class T> dual<T> expm1(const dual<T> & x); template<class T> dual<T> tanh_impl(const dual<T> & x) { using std::tanh; return dual<T>(tanh(x.rpart()), x.dpart() * (1 - tanh(x.rpart()) * tanh(x.rpart()))); } template<class T> dual<T> asinh_impl(const dual<T> & x) { using std::asinh; using std::sqrt; return dual<T>(asinh(x.rpart()), x.dpart() / sqrt(1 + x.rpart() * x.rpart())); } template<class T> dual<T> acosh_impl(const dual<T> & x) { using std::acosh; using std::sqrt; return dual<T>(acosh(x.rpart()), x.dpart() / sqrt(x.rpart() * x.rpart() - 1)); } template<class T> dual<T> atanh_impl(const dual<T> & x) { using std::atanh; return dual<T>(atanh(x.rpart()), x.dpart() / (1 - x.rpart() * x.rpart())); } template<class T> dual<T> log1p_impl(const dual<T> & x) { using std::log1p; return dual<T>(log1p(x.rpart()), x.dpart() / (1 + x.rpart())); } template<class T> dual<T> expm1_impl(const dual<T> & x) { using std::expm1; using std::exp; return dual<T>(expm1(x.rpart()), x.dpart() * exp(x.rpart())); } /// The error function. Make sure to `#include <math.h>` before /// `#include <duals/dual>` to use this function. Loading Loading @@ -1678,45 +1725,58 @@ struct fmt::formatter<duals::dual<T>,Char> : public fmt::formatter<T,Char> { typedef fmt::formatter<T,Char> base; enum style { expr, star, pair } style_ = expr; fmt::detail::dynamic_format_specs<Char> specs_; FMT_CONSTEXPR auto parse(format_parse_context & ctx) -> decltype(ctx.begin()) { using handler_type = fmt::detail::dynamic_specs_handler<format_parse_context>; auto type = fmt::detail::type_constant<T, Char>::value; fmt::detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), type); detail::dynamic_format_specs<Char> specs_; FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); if (it != ctx.end()) if (it != ctx.end()) { switch (*it) { case '$': style_ = style::expr; ctx.advance_to(++it); break; case '*': style_ = style::star; ctx.advance_to(++it); break; case ',': style_ = style::pair; ctx.advance_to(++it); break; default: break; } parse_format_specs(ctx.begin(), ctx.end(), handler); return base::parse(ctx); } return parse_format_specs(it, ctx.end(), specs_, ctx, detail::type_constant<T, Char>::value); } template <typename FormatCtx> auto format(const duals::dual<T> & x, FormatCtx & ctx) -> decltype(ctx.out()) { format_to(ctx.out(), "("); if (style_ == style::pair) { base::format(x.rpart(), ctx); format_to(ctx.out(), ","); base::format(x.dpart(), ctx); return format_to(ctx.out(), ")"); auto format(const duals::dual<T> & x, FormatCtx & ctx) const -> decltype(ctx.out()) { auto specs = specs_; if (specs.dynamic()) { detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref, ctx); detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, specs.precision_ref, ctx); } auto out = ctx.out(); *out++ = '('; if (style_ == style::pair) { out = detail::write<Char>(out, x.rpart(), specs, ctx.locale()); *out++ = ','; out = detail::write<Char>(out, x.dpart(), specs, ctx.locale()); } else { if (x.rpart() || !x.dpart()) base::format(x.rpart(), ctx); out = detail::write<Char>(out, x.rpart(), specs, ctx.locale()); if (x.dpart()) { if (x.rpart() && x.dpart() >= 0 && specs_.sign != sign::plus) format_to(ctx.out(), "+"); base::format(x.dpart(), ctx); if (style_ == style::star) format_to(ctx.out(), "*e"); else format_to(ctx.out(), "_e"); if (std::is_same<typename std::decay<T>::type,float>::value) format_to(ctx.out(), "f"); if (std::is_same<typename std::decay<T>::type,long double>::value) format_to(ctx.out(), "l"); if (x.rpart() && x.dpart() >= 0) specs.set_sign(sign::plus); out = detail::write<Char>(out, x.dpart(), specs, ctx.locale()); if (style_ == style::star) { *out++ = '*'; *out++ = 'e'; } else { *out++ = '_'; *out++ = 'e'; } return format_to(ctx.out(), ")"); if (std::is_same<typename std::decay<T>::type,float>::value) *out++ = 'f'; if (std::is_same<typename std::decay<T>::type,long double>::value) *out++ = 'l'; } } *out++ = ')'; return out; } }; #endif // CPPDUALS_LIBFMT Loading Loading @@ -1751,11 +1811,9 @@ struct fmt::formatter<std::complex<T>,Char> : public fmt::formatter<T,Char> { typedef fmt::formatter<T,Char> base; enum style { expr, star, pair } style_ = expr; fmt::detail::dynamic_format_specs<Char> specs_; FMT_CONSTEXPR auto parse(format_parse_context & ctx) -> decltype(ctx.begin()) { using handler_type = fmt::detail::dynamic_specs_handler<format_parse_context>; auto type = fmt::detail::type_constant<T, Char>::value; fmt::detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), type); detail::dynamic_format_specs<Char> specs_; FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); if (it != ctx.end()) { switch (*it) { Loading @@ -1765,24 +1823,29 @@ struct fmt::formatter<std::complex<T>,Char> : public fmt::formatter<T,Char> default: break; } } parse_format_specs(ctx.begin(), ctx.end(), handler); //todo: fixup alignment return base::parse(ctx); // Let base parser handle any nested format chars first auto end = base::parse(ctx); // Now parse the format specs for this formatter parse_format_specs(end, ctx.end(), specs_, ctx, detail::type_constant<T, Char>::value); return end; } template <typename FormatCtx> auto format(const std::complex<T> & x, FormatCtx & ctx) -> decltype(ctx.out()) { auto format(const std::complex<T> & x, FormatCtx & ctx) const -> decltype(ctx.out()) { format_to(ctx.out(), "("); if (style_ == style::pair) { base::format(x.real(), ctx); format_to(ctx.out(), ","); base::format(x.imag(), ctx); return format_to(ctx.out(), ")"); } } else { if (x.real() || !x.imag()) base::format(x.real(), ctx); if (x.imag()) { if (x.real() && x.imag() >= 0 && specs_.sign != sign::plus) // The base formatter will handle the negative sign if (x.real() && x.imag() >= 0 && sign::plus != specs_.sign()) { format_to(ctx.out(), "+"); } base::format(x.imag(), ctx); if (style_ == style::star) format_to(ctx.out(), "*i"); Loading @@ -1791,10 +1854,10 @@ struct fmt::formatter<std::complex<T>,Char> : public fmt::formatter<T,Char> if (std::is_same<typename std::decay<T>::type,float>::value) format_to(ctx.out(), "f"); if (std::is_same<typename std::decay<T>::type,long double>::value) format_to(ctx.out(), "l"); } } return format_to(ctx.out(), ")"); } }; #endif // CPPDUALS_LIBFMT_COMPLEX #endif // CPPDUALS_DUAL tests/test_fmt.cpp +44 −4 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ #include <fmt/format.h> //#include <fmt/std.h> #define CPPDUALS_LIBFMT #define CPPDUALS_LIBFMT_COMPLEX #include <duals/dual> Loading Loading @@ -52,21 +53,33 @@ TEST(libfmt, complex_flags) { s = fmt::format("{}", 2. + 3i); EXPECT_EQ(s, "(2+3i)"); } TEST(libfmt, complex_flags_dollar) { std::string s; s = fmt::format("{:$}", 2. + 3i); EXPECT_EQ(s, "(2+3i)"); } TEST(libfmt, complex_flags_star) { std::string s; s = fmt::format("{:*}", 2. + 3i); EXPECT_EQ(s, "(2+3*i)"); } TEST(libfmt, complex_flags_star_f) { std::string s; s = fmt::format("{:*.1f}", 2. + 3i); EXPECT_EQ(s, "(2.0+3.0*i)"); } TEST(libfmt, complex_flags_comma) { std::string s; s = fmt::format("{:,.1f}", 2. + 3i); EXPECT_EQ(s, "(2.0,3.0)"); s = fmt::format("{:,}", 2. + 3i); EXPECT_EQ(s, "(2,3)"); } TEST(libfmt, complex_flags_a) { std::string s; // + + s = fmt::format("{:$+}", 2. + 3i); Loading @@ -80,6 +93,10 @@ TEST(libfmt, complex_flags) { s = fmt::format("{:,+}", 2. + 3i); EXPECT_EQ(s, "(+2,+3)"); } TEST(libfmt, complex_flags_b) { std::string s; // + - s = fmt::format("{:$+}", 2. - 3i); Loading @@ -95,6 +112,7 @@ TEST(libfmt, complex_flags) { EXPECT_EQ(s, "(+2.0,-3.0)"); } TEST(libfmt, complex_all_real) { std::string s; s = fmt::format("{}", 2. + 0i); Loading @@ -112,6 +130,7 @@ TEST(libfmt, complex_all_real) { s = fmt::format("{:,.1f}", 2. + 0i); EXPECT_EQ(s, "(2.0,0.0)"); } TEST(libfmt, complex_all_imag) { std::string s; Loading Loading @@ -237,6 +256,17 @@ TEST(libfmt, dual_all_dual) { s = fmt::format("a{:,.1f}b", 0 + 3_e); EXPECT_EQ(s, "a(0.0,3.0)b"); } TEST(libfmt, dual_plus) { std::string s = fmt::format("{:+}", 1. + 3_e); EXPECT_EQ(s, "(+1+3_e)"); s = fmt::format("{:+.1f}", 1. + 3_e); EXPECT_EQ(s, "(+1.0+3.0_e)"); s = fmt::format("{:+}", 1. - 3_e); EXPECT_EQ(s, "(+1-3_e)"); } TEST(libfmt, dual_g) { std::string s = fmt::format("{:g}", 2 + 3_ef); EXPECT_EQ(s, "(2+3_ef)"); Loading @@ -252,6 +282,12 @@ TEST(libfmt, dual_gel) { std::string s = fmt::format("{:g}", 2 + 3_el); EXPECT_EQ(s, "(2+3_el)"); } TEST(libfmt, dual_cd) { std::string s = fmt::format("{}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)"); } TEST(libfmt, dual_cgt) { std::string s = fmt::format("{:g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)"); Loading @@ -266,6 +302,10 @@ TEST(libfmt, dual_cgts) { s = fmt::format("{:,*g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2+3*ef),(4+5*ef))"); // nonsense but should still work s = fmt::format("{:*,g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2,3)+(4,5)*i)"); s = fmt::format("{:,,g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2,3),(4,5))"); } tests/test_funcs.cpp +8 −6 Original line number Diff line number Diff line Loading @@ -85,12 +85,14 @@ FD_CHECK(double, hypot2LR, {-10.,-1.,0.01,1.,10.}) #define scalbnL(x) scalbn(x,2) FD_CHECK(double, scalbnL, {-10.,-1.,0.01,1.,10.}) //FD_CHECK(double, sinh, {0}) //FD_CHECK(double, cosh, {0}) //FD_CHECK(double, tanh, {0}) //FD_CHECK(double, asinh, {0}) //FD_CHECK(double, acosh, {0}) //FD_CHECK(double, atanh, {0}) FD_CHECK(double, sinh, {-0.1, 0.1}) FD_CHECK(double, cosh, {-0.1, 0.1}) FD_CHECK(double, tanh, {-0.1, 0.1}) FD_CHECK(double, asinh, {-0.1, 0.1}) FD_CHECK(double, acosh, {-1.1, 1.1}) FD_CHECK(double, atanh, {-0.1, 0.1}) FD_CHECK(double, log1p, {-0.1, 0.1}) FD_CHECK(double, expm1, {-0.1, 0.1}) FD_CHECK(double, erf, {-1,0,1}) FD_CHECK(double, erfc, {-1,0,1}) Loading thirdparty/CMakeLists.txt +2 −2 Original line number Diff line number Diff line Loading @@ -129,8 +129,8 @@ endif (hasParent) # ExternalProject_Add (fmtX PREFIX fmtX URL https://github.com/fmtlib/fmt/archive/7.1.3.tar.gz URL_HASH MD5=2522ec65070c0bda0ca288677ded2831 URL https://github.com/fmtlib/fmt/archive/11.1.4.tar.gz URL_HASH MD5=10c2ae163accd3b82e6b8b4dff877645 DOWNLOAD_DIR ${DOWNLOAD_DIR} CONFIGURE_COMMAND "" BUILD_COMMAND "" Loading Loading
CMakeLists.txt +1 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ # cmake_minimum_required (VERSION 3.14) project (cppduals VERSION 0.6.1 VERSION 0.6.2 LANGUAGES C CXX ) include (GNUInstallDirs) Loading
duals/dual +134 −71 Original line number Diff line number Diff line Loading @@ -861,6 +861,8 @@ namespace detail { template<class T> bool isnan_impl(const dual<T> & x); template<class T> bool signbit_impl(const dual<T> & x); template<class T> dual<T> copysign_impl(const dual<T> & x, const dual<T> & y); template<class T> dual<T> log1p_impl(const dual<T> & x); template<class T> dual<T> expm1_impl(const dual<T> & x); template<class T> dual<T> random_impl(const dual<T> & low, const dual<T> & high); template<class T> dual<T> random2_impl(const dual<T> & low, const dual<T> & high); } Loading Loading @@ -942,8 +944,8 @@ template <typename T> int sgn(T val) { } } template<class T> dual<T> log1p(const dual<T> & x); template<class T> dual<T> expm1(const dual<T> & x); template<class T> dual<T> log1p(const dual<T> & x) {return detail::log1p_impl(x);} template<class T> dual<T> expm1(const dual<T> & x) {return detail::expm1_impl(x);} #if __cpp_user_defined_literals >= 200809 /// Dual number literals in namespace duals::literals Loading Loading @@ -1371,22 +1373,67 @@ atan2_scalar_dual(const U & y, const dual<T> & x) { } template<class T> duals::dual<T> hypot_impl(const duals::dual<T> & x, const duals::dual<T> & y) { return sqrt(x*x + y*y); using std::hypot; return dual<T>(hypot(x.rpart(), y.rpart()), (x.rpart() * y.dpart() + y.rpart() * x.dpart()) / hypot(x.rpart(), y.rpart())); } template<class T> duals::dual<T> scalbn_impl(const duals::dual<T> & arg, int ex) { return arg * std::pow((T)2, ex); } template<class T> dual<T> sinh(const dual<T> & x); template<class T> dual<T> cosh(const dual<T> & x); template<class T> dual<T> tanh(const dual<T> & x); template<class T> dual<T> asinh(const dual<T> & x); template<class T> dual<T> acosh(const dual<T> & x); template<class T> dual<T> atanh(const dual<T> & x); template<class T> dual<T> sinh_impl(const dual<T> & x) { using std::sinh; using std::cosh; return dual<T>(sinh(x.rpart()), x.dpart() * cosh(x.rpart())); } template<class T> dual<T> cosh_impl(const dual<T> & x) { using std::cosh; using std::sinh; return dual<T>(cosh(x.rpart()), x.dpart() * sinh(x.rpart())); } //template<class T> dual<T> log1p(const dual<T> & x); //template<class T> dual<T> expm1(const dual<T> & x); template<class T> dual<T> tanh_impl(const dual<T> & x) { using std::tanh; return dual<T>(tanh(x.rpart()), x.dpart() * (1 - tanh(x.rpart()) * tanh(x.rpart()))); } template<class T> dual<T> asinh_impl(const dual<T> & x) { using std::asinh; using std::sqrt; return dual<T>(asinh(x.rpart()), x.dpart() / sqrt(1 + x.rpart() * x.rpart())); } template<class T> dual<T> acosh_impl(const dual<T> & x) { using std::acosh; using std::sqrt; return dual<T>(acosh(x.rpart()), x.dpart() / sqrt(x.rpart() * x.rpart() - 1)); } template<class T> dual<T> atanh_impl(const dual<T> & x) { using std::atanh; return dual<T>(atanh(x.rpart()), x.dpart() / (1 - x.rpart() * x.rpart())); } template<class T> dual<T> log1p_impl(const dual<T> & x) { using std::log1p; return dual<T>(log1p(x.rpart()), x.dpart() / (1 + x.rpart())); } template<class T> dual<T> expm1_impl(const dual<T> & x) { using std::expm1; using std::exp; return dual<T>(expm1(x.rpart()), x.dpart() * exp(x.rpart())); } /// The error function. Make sure to `#include <math.h>` before /// `#include <duals/dual>` to use this function. Loading Loading @@ -1678,45 +1725,58 @@ struct fmt::formatter<duals::dual<T>,Char> : public fmt::formatter<T,Char> { typedef fmt::formatter<T,Char> base; enum style { expr, star, pair } style_ = expr; fmt::detail::dynamic_format_specs<Char> specs_; FMT_CONSTEXPR auto parse(format_parse_context & ctx) -> decltype(ctx.begin()) { using handler_type = fmt::detail::dynamic_specs_handler<format_parse_context>; auto type = fmt::detail::type_constant<T, Char>::value; fmt::detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), type); detail::dynamic_format_specs<Char> specs_; FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); if (it != ctx.end()) if (it != ctx.end()) { switch (*it) { case '$': style_ = style::expr; ctx.advance_to(++it); break; case '*': style_ = style::star; ctx.advance_to(++it); break; case ',': style_ = style::pair; ctx.advance_to(++it); break; default: break; } parse_format_specs(ctx.begin(), ctx.end(), handler); return base::parse(ctx); } return parse_format_specs(it, ctx.end(), specs_, ctx, detail::type_constant<T, Char>::value); } template <typename FormatCtx> auto format(const duals::dual<T> & x, FormatCtx & ctx) -> decltype(ctx.out()) { format_to(ctx.out(), "("); if (style_ == style::pair) { base::format(x.rpart(), ctx); format_to(ctx.out(), ","); base::format(x.dpart(), ctx); return format_to(ctx.out(), ")"); auto format(const duals::dual<T> & x, FormatCtx & ctx) const -> decltype(ctx.out()) { auto specs = specs_; if (specs.dynamic()) { detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref, ctx); detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, specs.precision_ref, ctx); } auto out = ctx.out(); *out++ = '('; if (style_ == style::pair) { out = detail::write<Char>(out, x.rpart(), specs, ctx.locale()); *out++ = ','; out = detail::write<Char>(out, x.dpart(), specs, ctx.locale()); } else { if (x.rpart() || !x.dpart()) base::format(x.rpart(), ctx); out = detail::write<Char>(out, x.rpart(), specs, ctx.locale()); if (x.dpart()) { if (x.rpart() && x.dpart() >= 0 && specs_.sign != sign::plus) format_to(ctx.out(), "+"); base::format(x.dpart(), ctx); if (style_ == style::star) format_to(ctx.out(), "*e"); else format_to(ctx.out(), "_e"); if (std::is_same<typename std::decay<T>::type,float>::value) format_to(ctx.out(), "f"); if (std::is_same<typename std::decay<T>::type,long double>::value) format_to(ctx.out(), "l"); if (x.rpart() && x.dpart() >= 0) specs.set_sign(sign::plus); out = detail::write<Char>(out, x.dpart(), specs, ctx.locale()); if (style_ == style::star) { *out++ = '*'; *out++ = 'e'; } else { *out++ = '_'; *out++ = 'e'; } return format_to(ctx.out(), ")"); if (std::is_same<typename std::decay<T>::type,float>::value) *out++ = 'f'; if (std::is_same<typename std::decay<T>::type,long double>::value) *out++ = 'l'; } } *out++ = ')'; return out; } }; #endif // CPPDUALS_LIBFMT Loading Loading @@ -1751,11 +1811,9 @@ struct fmt::formatter<std::complex<T>,Char> : public fmt::formatter<T,Char> { typedef fmt::formatter<T,Char> base; enum style { expr, star, pair } style_ = expr; fmt::detail::dynamic_format_specs<Char> specs_; FMT_CONSTEXPR auto parse(format_parse_context & ctx) -> decltype(ctx.begin()) { using handler_type = fmt::detail::dynamic_specs_handler<format_parse_context>; auto type = fmt::detail::type_constant<T, Char>::value; fmt::detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), type); detail::dynamic_format_specs<Char> specs_; FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); if (it != ctx.end()) { switch (*it) { Loading @@ -1765,24 +1823,29 @@ struct fmt::formatter<std::complex<T>,Char> : public fmt::formatter<T,Char> default: break; } } parse_format_specs(ctx.begin(), ctx.end(), handler); //todo: fixup alignment return base::parse(ctx); // Let base parser handle any nested format chars first auto end = base::parse(ctx); // Now parse the format specs for this formatter parse_format_specs(end, ctx.end(), specs_, ctx, detail::type_constant<T, Char>::value); return end; } template <typename FormatCtx> auto format(const std::complex<T> & x, FormatCtx & ctx) -> decltype(ctx.out()) { auto format(const std::complex<T> & x, FormatCtx & ctx) const -> decltype(ctx.out()) { format_to(ctx.out(), "("); if (style_ == style::pair) { base::format(x.real(), ctx); format_to(ctx.out(), ","); base::format(x.imag(), ctx); return format_to(ctx.out(), ")"); } } else { if (x.real() || !x.imag()) base::format(x.real(), ctx); if (x.imag()) { if (x.real() && x.imag() >= 0 && specs_.sign != sign::plus) // The base formatter will handle the negative sign if (x.real() && x.imag() >= 0 && sign::plus != specs_.sign()) { format_to(ctx.out(), "+"); } base::format(x.imag(), ctx); if (style_ == style::star) format_to(ctx.out(), "*i"); Loading @@ -1791,10 +1854,10 @@ struct fmt::formatter<std::complex<T>,Char> : public fmt::formatter<T,Char> if (std::is_same<typename std::decay<T>::type,float>::value) format_to(ctx.out(), "f"); if (std::is_same<typename std::decay<T>::type,long double>::value) format_to(ctx.out(), "l"); } } return format_to(ctx.out(), ")"); } }; #endif // CPPDUALS_LIBFMT_COMPLEX #endif // CPPDUALS_DUAL
tests/test_fmt.cpp +44 −4 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ #include <fmt/format.h> //#include <fmt/std.h> #define CPPDUALS_LIBFMT #define CPPDUALS_LIBFMT_COMPLEX #include <duals/dual> Loading Loading @@ -52,21 +53,33 @@ TEST(libfmt, complex_flags) { s = fmt::format("{}", 2. + 3i); EXPECT_EQ(s, "(2+3i)"); } TEST(libfmt, complex_flags_dollar) { std::string s; s = fmt::format("{:$}", 2. + 3i); EXPECT_EQ(s, "(2+3i)"); } TEST(libfmt, complex_flags_star) { std::string s; s = fmt::format("{:*}", 2. + 3i); EXPECT_EQ(s, "(2+3*i)"); } TEST(libfmt, complex_flags_star_f) { std::string s; s = fmt::format("{:*.1f}", 2. + 3i); EXPECT_EQ(s, "(2.0+3.0*i)"); } TEST(libfmt, complex_flags_comma) { std::string s; s = fmt::format("{:,.1f}", 2. + 3i); EXPECT_EQ(s, "(2.0,3.0)"); s = fmt::format("{:,}", 2. + 3i); EXPECT_EQ(s, "(2,3)"); } TEST(libfmt, complex_flags_a) { std::string s; // + + s = fmt::format("{:$+}", 2. + 3i); Loading @@ -80,6 +93,10 @@ TEST(libfmt, complex_flags) { s = fmt::format("{:,+}", 2. + 3i); EXPECT_EQ(s, "(+2,+3)"); } TEST(libfmt, complex_flags_b) { std::string s; // + - s = fmt::format("{:$+}", 2. - 3i); Loading @@ -95,6 +112,7 @@ TEST(libfmt, complex_flags) { EXPECT_EQ(s, "(+2.0,-3.0)"); } TEST(libfmt, complex_all_real) { std::string s; s = fmt::format("{}", 2. + 0i); Loading @@ -112,6 +130,7 @@ TEST(libfmt, complex_all_real) { s = fmt::format("{:,.1f}", 2. + 0i); EXPECT_EQ(s, "(2.0,0.0)"); } TEST(libfmt, complex_all_imag) { std::string s; Loading Loading @@ -237,6 +256,17 @@ TEST(libfmt, dual_all_dual) { s = fmt::format("a{:,.1f}b", 0 + 3_e); EXPECT_EQ(s, "a(0.0,3.0)b"); } TEST(libfmt, dual_plus) { std::string s = fmt::format("{:+}", 1. + 3_e); EXPECT_EQ(s, "(+1+3_e)"); s = fmt::format("{:+.1f}", 1. + 3_e); EXPECT_EQ(s, "(+1.0+3.0_e)"); s = fmt::format("{:+}", 1. - 3_e); EXPECT_EQ(s, "(+1-3_e)"); } TEST(libfmt, dual_g) { std::string s = fmt::format("{:g}", 2 + 3_ef); EXPECT_EQ(s, "(2+3_ef)"); Loading @@ -252,6 +282,12 @@ TEST(libfmt, dual_gel) { std::string s = fmt::format("{:g}", 2 + 3_el); EXPECT_EQ(s, "(2+3_el)"); } TEST(libfmt, dual_cd) { std::string s = fmt::format("{}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)"); } TEST(libfmt, dual_cgt) { std::string s = fmt::format("{:g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)"); Loading @@ -266,6 +302,10 @@ TEST(libfmt, dual_cgts) { s = fmt::format("{:,*g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2+3*ef),(4+5*ef))"); // nonsense but should still work s = fmt::format("{:*,g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2,3)+(4,5)*i)"); s = fmt::format("{:,,g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2,3),(4,5))"); }
tests/test_funcs.cpp +8 −6 Original line number Diff line number Diff line Loading @@ -85,12 +85,14 @@ FD_CHECK(double, hypot2LR, {-10.,-1.,0.01,1.,10.}) #define scalbnL(x) scalbn(x,2) FD_CHECK(double, scalbnL, {-10.,-1.,0.01,1.,10.}) //FD_CHECK(double, sinh, {0}) //FD_CHECK(double, cosh, {0}) //FD_CHECK(double, tanh, {0}) //FD_CHECK(double, asinh, {0}) //FD_CHECK(double, acosh, {0}) //FD_CHECK(double, atanh, {0}) FD_CHECK(double, sinh, {-0.1, 0.1}) FD_CHECK(double, cosh, {-0.1, 0.1}) FD_CHECK(double, tanh, {-0.1, 0.1}) FD_CHECK(double, asinh, {-0.1, 0.1}) FD_CHECK(double, acosh, {-1.1, 1.1}) FD_CHECK(double, atanh, {-0.1, 0.1}) FD_CHECK(double, log1p, {-0.1, 0.1}) FD_CHECK(double, expm1, {-0.1, 0.1}) FD_CHECK(double, erf, {-1,0,1}) FD_CHECK(double, erfc, {-1,0,1}) Loading
thirdparty/CMakeLists.txt +2 −2 Original line number Diff line number Diff line Loading @@ -129,8 +129,8 @@ endif (hasParent) # ExternalProject_Add (fmtX PREFIX fmtX URL https://github.com/fmtlib/fmt/archive/7.1.3.tar.gz URL_HASH MD5=2522ec65070c0bda0ca288677ded2831 URL https://github.com/fmtlib/fmt/archive/11.1.4.tar.gz URL_HASH MD5=10c2ae163accd3b82e6b8b4dff877645 DOWNLOAD_DIR ${DOWNLOAD_DIR} CONFIGURE_COMMAND "" BUILD_COMMAND "" Loading