Created
November 1, 2017 22:59
-
-
Save arrieta/1d2f4bf34de2ca89626209aba2587723 to your computer and use it in GitHub Desktop.
C++ implementation of linspace.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -*- coding:utf-8; mode:c++; mode:auto-fill; fill-column:80; -*- | |
/// @file example-linspace.cpp | |
/// @brief Sample use of Nabla Zero Labs' linspace utilities. | |
/// @author J. Arrieta <[email protected]> | |
/// @date November 01, 2017 | |
/// @copyright (c) 2017 Nabla Zero Labs | |
/// @license MIT License | |
// C++ Standard Library | |
#include <iomanip> | |
#include <iostream> | |
#include <list> | |
#include <vector> | |
// Nabla Zero Labs Library | |
#include "linspace.hpp" | |
template <typename T> | |
void run_example() { | |
auto p = std::numeric_limits<T>::max_digits10; | |
auto w = p + 7; | |
std::cout << std::setprecision(p) << std::scientific; | |
// low-level iterator interface | |
auto it = nzl::linspace_iterator<T>(-10, 10, 5); | |
auto it_end = nzl::linspace_iterator<T>{}; // sentinel | |
std::cout << "linspace_iterator\n"; | |
for (auto count = 0; it != it_end; ++it) { | |
std::cout << " linspace[" << count++ << "] = " << std::setw(w) << *it | |
<< "\n"; | |
} | |
// range-based for (also ilustrating decreasing values) | |
std::cout << "range-based\n"; | |
for (auto&& value : nzl::linspace<T>(10, -5, 6)) { | |
std::cout << " " << std::setw(w) << value << "\n"; | |
} | |
// fill exising containers | |
std::vector<T> v; | |
v.resize(7); | |
nzl::fill_linspace(v, -8, 3); | |
std::cout << "fill vector\n"; | |
for (auto&& vi : v) std::cout << " " << std::setw(w) << vi << "\n"; | |
// only the first five elements | |
std::list<T> l; | |
l.resize(10); | |
nzl::fill_linspace_n(l.begin(), -1, 3, 5); | |
std::cout << "fill elements [0, 5) in list\n"; | |
for (auto&& li : l) std::cout << " " << std::setw(w) << li << "\n"; | |
// put a linspace in a new container | |
auto x = nzl::as_linspace<std::vector<T>>(-3, 8, 10); | |
std::cout << "create container\n"; | |
for (auto&& xi : x) std::cout << " " << std::setw(w) << xi << "\n"; | |
} | |
int main() { | |
std::cout << "float\n"; | |
run_example<float>(); | |
std::cout << "double\n"; | |
run_example<double>(); | |
std::cout << "long double\n"; | |
run_example<long double>(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -*- coding:utf-8; mode:c++; mode:auto-fill; fill-column:80; -*- | |
/// @file nzl/linspace.hpp | |
/// @brief Generate an linear space of floating point numbers. | |
/// @author J. Arrieta <[email protected]> | |
/// @date November 01, 2017 | |
/// @copyright (c) 2017 Nabla Zero Labs | |
/// @license MIT License | |
#pragma once | |
#ifndef NZL_LINSPACE_HPP_HEADER_GUARD | |
#define NZL_LINSPACE_HPP_HEADER_GUARD | |
// C++ Standard Library | |
#include <cstddef> | |
#include <iterator> | |
#include <limits> | |
namespace nzl { | |
/// @brief Iterator producing elements of a linear space. | |
template <typename T> // T is any floating point type | |
class linspace_iterator { | |
public: | |
using iterator_category = std::input_iterator_tag; | |
using value_type = T; | |
using reference = T&; | |
using pointer = T*; | |
using difference_type = std::size_t; | |
static_assert( | |
std::is_floating_point<T>::value, | |
"nzl::linspace_iterator is only defined for floating point types"); | |
explicit linspace_iterator() noexcept(true) | |
: m_remaining{std::numeric_limits<std::size_t>::max()} {} | |
linspace_iterator(T first, T last, std::size_t n) noexcept(true) | |
: m_remaining{n - 1}, | |
m_current{std::move(first)}, | |
m_step{(last - m_current) / m_remaining}, | |
m_final{std::move(last)} {} | |
linspace_iterator<T>& operator++() { | |
this->next(); | |
return *this; | |
} | |
linspace_iterator<T> operator++(int) { | |
auto tmp = *this; | |
this->next(); | |
return tmp; | |
} | |
const value_type& operator*() const { return m_current; } | |
const value_type* operator->() const { return std::addressof(*this); } | |
bool operator!=(const linspace_iterator<T>& other) { | |
return not(*this == other); | |
} | |
bool operator==(const linspace_iterator<T>& other) { | |
return ((this->is_invalid() and other.is_invalid()) or | |
std::memcmp(this, &other, sizeof(other)) == 0); | |
} | |
std::size_t size() const noexcept(true) { return m_remaining + 1; } | |
private: | |
bool is_invalid() const { | |
return m_remaining == std::numeric_limits<std::size_t>::max(); | |
} | |
void next() { | |
switch (m_remaining) { | |
case 1: | |
m_current = m_final; | |
--m_remaining; | |
break; | |
case 0: | |
m_remaining = std::numeric_limits<std::size_t>::max(); | |
break; | |
case std::numeric_limits<std::size_t>::max(): | |
break; | |
default: | |
m_current += m_step; | |
--m_remaining; | |
break; | |
} | |
} | |
std::size_t m_remaining; | |
T m_current; | |
T m_step; | |
T m_final; | |
}; | |
/// @brief Range containing a linear space of floating point numbers. | |
template <typename T> | |
class linspace { | |
public: | |
linspace(T first, T last, std::size_t n = 100) noexcept(true) | |
: m_it{first, last, n}, m_it_end{} {} | |
linspace_iterator<T> begin() const noexcept(true) { return m_it; } | |
linspace_iterator<T> end() const noexcept(true) { return m_it_end; } | |
std::size_t size() const noexcept(true) { return m_it.size(); } | |
private: | |
linspace_iterator<T> m_it; | |
linspace_iterator<T> m_it_end; | |
}; | |
/// @brief Fill a range with a linear space. | |
template <typename I> // I models InputIterator | |
inline void fill_linspace_n(I begin, typename I::value_type first, | |
typename I::value_type last, std::size_t n) { | |
std::copy(linspace_iterator<typename I::value_type>(first, last, n), | |
linspace_iterator<typename I::value_type>(), begin); | |
} | |
/// @brief Fill a range with a linear space. | |
template <typename I> // I models InputIterator | |
inline void fill_linspace(I begin, I end, typename I::value_type first, | |
typename I::value_type last) { | |
return fill_linspace_n(begin, first, last, std::distance(begin, end)); | |
} | |
/// @brief Fill an existing sequence with a linear space. | |
template <typename S> // S models SequenceContainer | |
inline S& fill_linspace(S& sequence_container, typename S::value_type first, | |
typename S::value_type last) { | |
fill_linspace_n(sequence_container.begin(), first, last, | |
sequence_container.size()); | |
return sequence_container; | |
} | |
/// @brief Create a sequence filled with a linear space. | |
template <typename S> // S models SequenceContainer | |
inline S as_linspace(typename S::value_type first, typename S::value_type last, | |
std::size_t n) { | |
return S(linspace_iterator<typename S::value_type>(first, last, n), | |
linspace_iterator<typename S::value_type>()); | |
} | |
} // namespace nzl | |
#endif // NZL_LINSPACE_HPP_HEADER_GUARD |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ clang++ example-linspace.cpp -std=c++17 -Wall -Wextra -Ofast -march=native | |
$ ./a.out | |
float | |
linspace_iterator | |
linspace[0] = -1.000000000e+01 | |
linspace[1] = -5.000000000e+00 | |
linspace[2] = 0.000000000e+00 | |
linspace[3] = 5.000000000e+00 | |
linspace[4] = 1.000000000e+01 | |
range-based | |
1.000000000e+01 | |
7.000000000e+00 | |
4.000000000e+00 | |
1.000000000e+00 | |
-2.000000000e+00 | |
-5.000000000e+00 | |
fill vector | |
-8.000000000e+00 | |
-6.166666508e+00 | |
-4.333333015e+00 | |
-2.499999523e+00 | |
-6.666661501e-01 | |
1.166667223e+00 | |
3.000000000e+00 | |
fill elements [0, 5) in list | |
-1.000000000e+00 | |
0.000000000e+00 | |
1.000000000e+00 | |
2.000000000e+00 | |
3.000000000e+00 | |
0.000000000e+00 | |
0.000000000e+00 | |
0.000000000e+00 | |
0.000000000e+00 | |
0.000000000e+00 | |
create container | |
-3.000000000e+00 | |
-1.777777791e+00 | |
-5.555555820e-01 | |
6.666666269e-01 | |
1.888888836e+00 | |
3.111111164e+00 | |
4.333333492e+00 | |
5.555555820e+00 | |
6.777778149e+00 | |
8.000000000e+00 | |
double | |
linspace_iterator | |
linspace[0] = -1.00000000000000000e+01 | |
linspace[1] = -5.00000000000000000e+00 | |
linspace[2] = 0.00000000000000000e+00 | |
linspace[3] = 5.00000000000000000e+00 | |
linspace[4] = 1.00000000000000000e+01 | |
range-based | |
1.00000000000000000e+01 | |
7.00000000000000000e+00 | |
4.00000000000000000e+00 | |
1.00000000000000000e+00 | |
-2.00000000000000000e+00 | |
-5.00000000000000000e+00 | |
fill vector | |
-8.00000000000000000e+00 | |
-6.16666666666666696e+00 | |
-4.33333333333333393e+00 | |
-2.50000000000000089e+00 | |
-6.66666666666667629e-01 | |
1.16666666666666563e+00 | |
3.00000000000000000e+00 | |
fill elements [0, 5) in list | |
-1.00000000000000000e+00 | |
0.00000000000000000e+00 | |
1.00000000000000000e+00 | |
2.00000000000000000e+00 | |
3.00000000000000000e+00 | |
0.00000000000000000e+00 | |
0.00000000000000000e+00 | |
0.00000000000000000e+00 | |
0.00000000000000000e+00 | |
0.00000000000000000e+00 | |
create container | |
-3.00000000000000000e+00 | |
-1.77777777777777768e+00 | |
-5.55555555555555358e-01 | |
6.66666666666666963e-01 | |
1.88888888888888928e+00 | |
3.11111111111111160e+00 | |
4.33333333333333393e+00 | |
5.55555555555555625e+00 | |
6.77777777777777857e+00 | |
8.00000000000000000e+00 | |
long double | |
linspace_iterator | |
linspace[0] = -1.000000000000000000000e+01 | |
linspace[1] = -5.000000000000000000000e+00 | |
linspace[2] = 0.000000000000000000000e+00 | |
linspace[3] = 5.000000000000000000000e+00 | |
linspace[4] = 1.000000000000000000000e+01 | |
range-based | |
1.000000000000000000000e+01 | |
7.000000000000000000000e+00 | |
4.000000000000000000000e+00 | |
1.000000000000000000000e+00 | |
-2.000000000000000000000e+00 | |
-5.000000000000000000000e+00 | |
fill vector | |
-8.000000000000000000000e+00 | |
-6.166666666666666666522e+00 | |
-4.333333333333333333044e+00 | |
-2.499999999999999999566e+00 | |
-6.666666666666666661968e-01 | |
1.166666666666666667173e+00 | |
3.000000000000000000000e+00 | |
fill elements [0, 5) in list | |
-1.000000000000000000000e+00 | |
0.000000000000000000000e+00 | |
1.000000000000000000000e+00 | |
2.000000000000000000000e+00 | |
3.000000000000000000000e+00 | |
0.000000000000000000000e+00 | |
0.000000000000000000000e+00 | |
0.000000000000000000000e+00 | |
0.000000000000000000000e+00 | |
0.000000000000000000000e+00 | |
create container | |
-3.000000000000000000000e+00 | |
-1.777777777777777777754e+00 | |
-5.555555555555555555074e-01 | |
6.666666666666666667389e-01 | |
1.888888888888888888985e+00 | |
3.111111111111111111232e+00 | |
4.333333333333333333478e+00 | |
5.555555555555555555941e+00 | |
6.777777777777777777971e+00 | |
8.000000000000000000000e+00 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment