C++ 基于元素间差异的生成器获取

C++ 基于元素间差异的生成器获取,c++,c++14,range-v3,C++,C++14,Range V3,我试图从休斯1989年的《为什么函数编程很重要》中,对牛顿-拉斐逊平方根算法的函数版本进行近似 我很欣赏任何关于替代方法的建议:越多越好。我目前的方法使用Niebler的range-v3。您将在代码片段中看到,我创建了一个生成器来创建连续的迭代并将它们插入到流中。我的问题是终止条件。我需要检测流中连续浮点数之间的差值何时低于阈值: #include <iostream> #include <range/v3/all.hpp> using namespace ranges

我试图从休斯1989年的《为什么函数编程很重要》中,对牛顿-拉斐逊平方根算法的函数版本进行近似

我很欣赏任何关于替代方法的建议:越多越好。我目前的方法使用Niebler的range-v3。您将在代码片段中看到,我创建了一个生成器来创建连续的迭代并将它们插入到流中。我的问题是终止条件。我需要检测流中连续浮点数之间的差值何时低于阈值:

#include <iostream>
#include <range/v3/all.hpp>

using namespace ranges::view;

int main() {

  auto sqrt_stream = generate([ x = 1.f, n = 3.f ]() mutable {
    auto prevx = x;
    x = (x + n / x) / 2;
    return prevx;
  });

  std::vector<float> sequence = sqrt_stream | take_while([](int x) { ??? });

  return 0;
}
#包括
#包括
使用命名空间范围::视图;
int main(){
auto sqrt_stream=generate([x=1.f,n=3.f]()可变{
自动prevx=x;
x=(x+n/x)/2;
返回prevx;
});
std::vector sequence=sqrt_stream|take_while([](int x){???});
返回0;
}

我不知道如何获得任何购买来比较连续元素,例如简单的远期差异。即使我这样做了,一旦我将流转换为正向差分,我将如何从生成器中恢复适当的元素?

我能想到的最简单的解决方案是生成序列元素对并按连续差分进行过滤():


这必然省略了序列中的第一个估计值。

< P>我从伊凡的UKI中得到了一个建议,这是即将到来的C++函数编程的作者。他给了我与+Casey相同的建议,使用pairs,尽管我对实现做了一些不同的充实,并使其通用化。我用zip做成对的(2元组)。下面是完整的解决方案,供任何好奇的人将来参考

我对代码不满意。它当然不漂亮,我觉得有很大的空间让头脑清醒的人来简化它。但我把时间都花在了投资上。欢迎进一步改进

#include <iostream>
#include <list>
#include <range/v3/all.hpp>

using namespace ranges::view;

// create a lazy stream given a function f and a seed value a0.
// stream will contain [a0, f(a0), f(f(a0)), f(f(f(a0))),...]
template <typename T> //
auto repeat_stream(std::function<T(T)> f, T a0) {
  return generate([ f, a = a0 ]() mutable {
    auto prev = a;
    a = f(a);
    return prev;
  });
}

// Consumes a stream until cosnecutive values differ within eps, and then the
// latest value is returned.
template <typename E, typename T>
E within(E eps, T v) {
  std::list<std::tuple<E, E>> converging_list =
      zip(v, v | drop(1))
        | take_while([eps](std::tuple<E, E> x) {
            return std::abs(std::get<0>(x) - std::get<1>(x)) > eps;
        });
  return std::get<0>(converging_list.back());
}

// Newton-Raphson Square Roots
// A la Hughes 1989 "Why Functional Programming Matters"
// http://www.cs.utexas.edu/~shmat/courses/cs345/whyfp.pdf
float nr_sqrt(float x, float x0) {
  return within(
      1E-15,
      repeat_stream<float>([n = x](float a) { return (a + n / a) / 2; }, x0));
}

int main() {

  std::cout << nr_sqrt(9, 4) << std::endl;

  return 0;
}

如果有人知道如何通过自动类型推断来解析
std::function
,这样我就不必指定
fixedpoint
,我很乐意听到这个消息。

你可以让
take\u while
成为一个带有存储先前值的变量的闭包是的,绝对可以。这将是我的备用解决方案。我试图避免任何对状态的显式处理(这是为了演示文稿),但如果我做不到,那也没什么大不了的。如您所见,我在生成器中已经有了一些显式的局部状态。谈话的要点是如何使用C++在功能和命令性设计之间形成一种有趣的平衡。
#include <iostream>
#include <list>
#include <range/v3/all.hpp>

using namespace ranges::view;

// create a lazy stream given a function f and a seed value a0.
// stream will contain [a0, f(a0), f(f(a0)), f(f(f(a0))),...]
template <typename T> //
auto repeat_stream(std::function<T(T)> f, T a0) {
  return generate([ f, a = a0 ]() mutable {
    auto prev = a;
    a = f(a);
    return prev;
  });
}

// Consumes a stream until cosnecutive values differ within eps, and then the
// latest value is returned.
template <typename E, typename T>
E within(E eps, T v) {
  std::list<std::tuple<E, E>> converging_list =
      zip(v, v | drop(1))
        | take_while([eps](std::tuple<E, E> x) {
            return std::abs(std::get<0>(x) - std::get<1>(x)) > eps;
        });
  return std::get<0>(converging_list.back());
}

// Newton-Raphson Square Roots
// A la Hughes 1989 "Why Functional Programming Matters"
// http://www.cs.utexas.edu/~shmat/courses/cs345/whyfp.pdf
float nr_sqrt(float x, float x0) {
  return within(
      1E-15,
      repeat_stream<float>([n = x](float a) { return (a + n / a) / 2; }, x0));
}

int main() {

  std::cout << nr_sqrt(9, 4) << std::endl;

  return 0;
}
#include <cmath>
#include <functional>
#include <iostream>

using namespace std::placeholders;

template <typename T>
T fixedpoint(std::function<T(T)> f, T start, T eps) {

  std::function<T(T, T)> iter = [&iter, eps, &f](T old, T nw) -> T {
    if (std::abs(old - nw) < eps)
      return nw;
    else
      return iter(nw, f(nw));
  };

  return iter(start, f(start));
}

auto nr_step(double N, double a) { return (a + N / a) / 2; }

int main() {

  std::cout << fixedpoint<double>(std::bind(nr_step, 3, _1), 1.2, 1E-10)
            << std::endl;

  return 0;
}