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 because 3*3+4*4 = 9+16 = 25 = 5*5
6 8 10 because 6*6+8*8 = 36+64 = 100 = 10*10
5 12 13 because 5*5+12*12 = 25+144 = 169 = 13*13
This can be done as follows:
- Step through all sorted pairs of
a
andb
, soa < b
. - For each of these pairs go through all numbers
c
and check whethera²+b²=c²
holds true. - The trick is that given
c
the possible range ofa
andb
is small: it can only be between1
andc
. No need to even compute a square root!
main = print (take 10 triples)
triples = [(a, b, c) | c <- [1..]
, a <- [1..c]
, b <- [a..c]
, a^2 + b^2 == c^2]
package main
import "fmt"
func main() {
n := 0
for c := 1; ;c++ {
for a := 1; a < c; a++ {
for b := a; b < c; b++ {
if a*a+b*b == c*c {
fmt.Println(a, b, c)
n++
if n >= 10 {
return
}
}
}
}
}
}
#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';
}
}