I was pointed to a blog post about some new features in C++, the first language that I learnt when I started programming 15 years ago.
The author, a member of the C++ Standardization Committee, gives us an example of some basic algorithm to illustrate the use of a new C++ feature that he worked on. The task is rather simple: find triplets of integers a
, b
and c
where a²+b²=c²
. Here are some examples:
3 4 5
6 8 10
5 12 13
This can be done in a simple way:
- Step through all pairs of
a
andb
wherea < b
, this can be done in a nested for-loop. - For each of these pairs go through all numbers
c
wherec²
is less or equal toa²+b²
and see ifa²+b²=c²
holds true. No need to even compute a square root or anything like that.
main = print (take 10 triples)
triples = [(x, y, z) | z <- [1..]
, x <- [1..z]
, y <- [x..z]
, x^2 + y^2 == z^2]
package main
import (
"fmt"
)
func main() {
var a, b, c int
for i := 0; i < 10; i++ {
a, b, c = nextTriple(a, b, c)
fmt.Println(a, b, c)
}
}
func nextTriple(a, b, c int) (int, int, int) {
for {
a++
if a >= b {
b++
a = 1
}
want := a*a + b*b
c = a + 1
for c*c < want {
c++
}
if c*c == want {
return a, b, c
}
}
}
#include <iostream>
#include <optional>
#include <ranges>
using namespace std;
template<Semiregular T>
struct maybe_view : view_interface<maybe_view<T>> {
maybe_view() = default;
maybe_view(T t) : data_(std::move(t)) {}
T const *begin() const noexcept {
return data_ ? &*data_ : nullptr;
}
T const *end() const noexcept {
return data_ ? &*data_ + 1 : nullptr;
}
private:
optional<T> data_{};
};
inline constexpr auto for_each =
[]<Range R, Iterator I = iterator_t<R>,
IndirectUnaryInvocable<I> Fun>(R&& r, Fun fun)
requires Range<indirect_result_t<Fun, I>> {
return std::forward<R>(r)
| view::transform(std::move(fun))
| view::join;
};
inline constexpr auto yield_if =
[]<Semiregular T>(bool b, T x) {
return b ? maybe_view{std::move(x)} : maybe_view<T>{};
};
int main() {
using view::iota;
auto triples =
for_each(iota(1), [](int z) {
return for_each(iota(1, z+1), [=](int x) {
return for_each(iota(x, z+1), [=](int y) {
return yield_if(x*x + y*y == z*z, make_tuple(x, y, z));
});
});
});
for(auto triple : triples | view::take(10)) {
cout << '('
<< get<0>(triple) << ','
<< get<1>(triple) << ','
<< get<2>(triple) << ')' << '\n';
}
}