Commit 9f45c566 authored by Michael Tesch's avatar Michael Tesch
Browse files

Merge branch 'fx-fmt-11' into 'master'

Fx fmt 11

See merge request !39
parents 7ca1b0bf eddd9092
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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)
+134 −71
Original line number Diff line number Diff line
@@ -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);
}
@@ -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
@@ -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.
@@ -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
@@ -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) {
@@ -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");
@@ -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
+44 −4
Original line number Diff line number Diff line
@@ -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>
@@ -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);
@@ -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);
@@ -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);
@@ -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;

@@ -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)");
@@ -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)");
@@ -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))");
}
+8 −6
Original line number Diff line number Diff line
@@ -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})
+2 −2
Original line number Diff line number Diff line
@@ -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 ""