Skip to content

Instantly share code, notes, and snippets.

@2bbb
Last active March 27, 2019 15:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 2bbb/254ed9627643c7359395b9155fe20c90 to your computer and use it in GitHub Desktop.
Save 2bbb/254ed9627643c7359395b9155fe20c90 to your computer and use it in GitHub Desktop.
alt_float c++11
// original code (with C++14) by kazatsuyu (https://github.com/kazatsuyu)
// CC0 https://creativecommons.org/publicdomain/zero/1.0/deed.en
/*
CC0 1.0 Universal (CC0 1.0)
Public Domain Dedication
No Copyright
The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.
You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. See Other Information below.
This license is acceptable for Free Cultural Works.
Other Information
In no way are the patent or trademark rights of any person affected by CC0, nor are the rights that other persons may have in the work or in how the work is used, such as publicity or privacy rights.
Unless expressly stated otherwise, the person who associated a work with this deed makes no warranties about the work, and disclaims liability for all uses of the work, to the fullest extent permitted by applicable law.
When using or citing the work, you should not imply endorsement by the author or the affirmer.
*/
// https://qiita.com/kazatsuyu/items/1656e90b8ac0d999f12d
// https://twitter.com/kazatsuyu
// edit to fix for C++11 by ishii 2bit
#include <type_traits>
#include <cstdint>
#include <cstddef>
#include <numeric>
namespace bbb {
namespace alt_float {
template <bool b, typename t, typename f>
using conditional_t = typename std::conditional<b, t, f>::type;
}
namespace alt_float {
template<typename ...Args>
struct first_enabled {};
template<typename T, typename ...Args>
struct first_enabled<std::enable_if<true, T>, Args...> { using type = T; };
template<typename T, typename ...Args>
struct first_enabled<std::enable_if<false, T>, Args...>: first_enabled<Args...> {};
template<typename T, typename ...Args>
struct first_enabled<T, Args...> { using type = T; };
template<typename ...Args>
using first_enabled_t = typename first_enabled<Args...>::type;
}
namespace alt_float {
enum class f32_t : std::uint32_t {};
enum class f64_t : std::uint64_t {};
};
namespace alt_float {
template<int n>
using float_least_t = first_enabled_t<
std::enable_if<std::numeric_limits<float>::digits >= n, float>,
std::enable_if<std::numeric_limits<double>::digits >= n, double>,
long double
>;
template<typename T>
struct f_traits_base;
template<>
struct f_traits_base<f32_t>
{
using u_type = std::uint32_t;
static constexpr auto fraction_bits = 23;
static constexpr auto exponent_bits = 8;
};
template<>
struct f_traits_base<f64_t>
{
using u_type = std::uint64_t;
static constexpr auto fraction_bits = 52;
static constexpr auto exponent_bits = 11;
};
namespace ldexp_detail {
template <typename T>
struct pair {
const T x;
const int n;
constexpr pair(const T x, const int n)
: x(x), n(n)
{};
};
template <typename T>
constexpr pair<T> while_positive(const pair<T> p) noexcept {
#define lshift64 ((uint64_t{} -1) + T{1.})
#define rshift64 (T{1.} / lshift64)
return (64 <= p.n)
? while_positive(pair<T>{p.x * lshift64, p.n - 64})
: p.n
? pair<T>{p.x * (uint64_t{1} << p.n), p.n}
: p;
#undef lshift64
#undef rshift64
}
template <typename T>
constexpr pair<T> while_negative(const pair<T> p) noexcept {
#define lshift64 ((uint64_t{} -1) + T{1.})
#define rshift64 (T{1.} / lshift64)
return (p.n <= -64)
? while_negative(pair<T>{p.x * rshift64, p.n + 64})
: p.n
? pair<T>{p.x * rshift64 * 2 * (uint64_t{1} << (63 + p.n)), p.n}
: p;
#undef lshift64
#undef rshift64
}
};
template<typename T>
constexpr T ldexp(T x, int n) noexcept {
#define lshift64 ((uint64_t{} -1) + T{1.})
#define rshift64 (T{1.} / lshift64)
return (0 <= n)
? ldexp_detail::while_positive(ldexp_detail::pair<T>{x, n}).x
: ldexp_detail::while_negative(ldexp_detail::pair<T>{x, n}).x;
#undef lshift64
#undef rshift64
}
template<typename T>
constexpr T pow2(int n) noexcept { return ldexp(T{1.}, n); }
template<typename T>
struct f_traits
{
using base = f_traits_base<T>;
using u_type = typename base::u_type; // 同一サイズの符号なし整数型
static constexpr auto fraction_bits = base::fraction_bits; // IEEE 754の内部表現における基数部分のビット数
static constexpr auto exponent_bits = base::exponent_bits; // IEEE 754の内部表現における指数部分のビット数
using f_type = float_least_t<fraction_bits+1>; // 少なくとも(fraction+1)bitの精度を持つ浮動小数点数型
static constexpr auto fraction_mask = (u_type{1} << fraction_bits) -1; // and演算で基数部のみを取り出すためのマスク
static constexpr auto exponent_mask = (u_type{1} << exponent_bits) -1; // and演算で指数部のみを取り出すためのマスク
static constexpr auto sign_mask = u_type{1} << (fraction_bits + exponent_bits); // and演算で符号部のみを取り出すためのマスク
static constexpr auto bias = (1 << (exponent_bits-1))-1; // 指数部のバイアス
static constexpr auto denorm_min = pow2<f_type>(-fraction_bits-bias+1); // 最小の非正規化数の値
static constexpr auto norm_min = pow2<f_type>(-bias+1);
};
}
namespace alt_float {
template<bool cond>
using enable_when = typename std::enable_if<cond, std::nullptr_t>::type;
template<typename T>
struct is_alt_float : conditional_t<std::is_same<T, f32_t>{} || std::is_same<T, f64_t>{}, std::true_type, std::false_type> {};
template<typename T, typename U>
struct is_compatible : std::false_type {};
template<typename T>
struct is_compatible<T, f32_t> : conditional_t<std::is_same<T, typename f_traits<f32_t>::f_type>{}, std::true_type, std::false_type> {};
template<typename T>
struct is_compatible<T, f64_t> : conditional_t<std::is_same<T, typename f_traits<f64_t>::f_type>{}, std::true_type, std::false_type> {};
namespace cast_detail {
template <typename T, typename U>
struct pair {
const U value;
const decltype(f_traits<T>::bias + f_traits<T>::fraction_bits) e;
constexpr pair(U value, decltype(e) e)
: e(e), value(value) {};
};
template <typename T, typename U>
constexpr pair<T, U> while1(const pair<T, U> p) {
return p.value >= pow2<U>(f_traits<T>::fraction_bits + 1)
? while1<T, U>(pair<T, U>{p.value * static_cast<U>(0.5), p.e + 1})
: p;
}
template <typename T, typename U>
constexpr pair<T, U> while2(const pair<T, U> p) {
return p.value < pow2<U>(f_traits<T>::fraction_bits)
? while2<T, U>(pair<T, U>{p.value * static_cast<U>(2), p.e - 1})
: p;
}
template <typename T, typename U>
constexpr pair<T, U> while_mod(const pair<T, U> p)
{ return while2<T, U>(while1<T, U>(p)); }
}
template<typename T, typename U, enable_when<is_compatible<U, T>::value> = nullptr>
constexpr T cast(U value) noexcept {
using t = f_traits<T>;
using f_type = typename t::f_type;
using u_type = typename t::u_type;
#define fb (t::fraction_bits)
#define fm (t::fraction_mask)
#define em (t::exponent_mask)
#define sm (t::sign_mask)
#define nm (t::norm_min)
#define bi (t::bias)
#define sign (value < 0)
#define signed_value ((sign ? -1 : 1) * value)
#define RETURN(...) (static_cast<T>(sign ? sm | (__VA_ARGS__) : (__VA_ARGS__)))
return (value != value)
? static_cast<T>((em << fb) | fm)
: (signed_value == std::numeric_limits<f_type>::infinity())
? RETURN(em << fb)
: (signed_value < nm)
? RETURN(static_cast<u_type>(signed_value * pow2<U>(fb + bi - 1)))
: RETURN(
(
static_cast<u_type>(
cast_detail::while_mod<T, U>(
cast_detail::pair<T, U>{signed_value, bi + fb}
).e
)
<< fb
) | (
static_cast<u_type>(
cast_detail::while_mod<T, U>(
cast_detail::pair<T, U>{signed_value, bi + fb}
).value
) & fm
)
);
#undef fb
#undef fm
#undef em
#undef sm
#undef nm
#undef bi
#undef sign
#undef signed_value
#undef RETURN
}
template<typename T, typename U, enable_when<is_alt_float<T>::value && !is_alt_float<U>::value && !is_compatible<U, T>::value> = nullptr>
constexpr T cast(U value) noexcept(noexcept(static_cast<typename f_traits<T>::f_type>(value))) {
return cast<T>(static_cast<typename f_traits<T>::f_type>(value));
}
template<typename T, typename U, enable_when<is_compatible<T, U>::value> = nullptr>
constexpr T cast(U value) noexcept {
using t = f_traits<U>;
using u_type = typename t::u_type;
using limits = std::numeric_limits<T>;
#define fb (t::fraction_bits)
#define fm (t::fraction_mask)
#define em (t::exponent_mask)
#define sm (t::sign_mask)
#define bi (t::bias)
#define dm (t::denorm_min)
#define s (!!(static_cast<u_type>(value) & sm))
#define e ((static_cast<u_type>(value) >> fb) & em)
#define f (static_cast<u_type>(value) & fm)
#define RETURN(...) (s ? -(__VA_ARGS__) : __VA_ARGS__)
return (e == em)
? (!f)
? RETURN(limits::infinity())
: (f & (u_type{1} << (fb - 1)))
? RETURN(limits::quiet_NaN())
: RETURN(limits::signaling_NaN())
: (!e)
? RETURN(f * dm)
: RETURN(ldexp<T>(f | (u_type{1} << fb), e - fb - bi));
#undef fb
#undef fm
#undef em
#undef sm
#undef bi
#undef dm
#undef s
#undef e
#undef f
#undef RETURN
}
template<typename T, typename U, enable_when<is_alt_float<U>::value && !is_alt_float<T>::value && !is_compatible<T, U>::value> = nullptr>
constexpr T cast(U value) noexcept(noexcept(static_cast<T>(typename f_traits<U>::f_type{}))) {
return static_cast<T>(cast<typename f_traits<U>::f_type>(value));
}
template<typename T, typename U, enable_when<is_alt_float<U>::value && is_alt_float<T>::value> = nullptr>
constexpr T cast(U value) noexcept {
return cast<T>(cast<typename f_traits<U>::f_type>(value));
}
}
namespace alt_float {
inline namespace operators {
template<typename T, typename U> struct common_type : std::common_type<T, U> {};
template<> struct common_type<f32_t, f64_t> { using type = f64_t; };
template<> struct common_type<f64_t, f32_t> { using type = f64_t; };
template<typename T, typename U>
using common_type_t = typename common_type<T, U>::type;
template<typename T, enable_when<is_alt_float<T>::value> = nullptr>
constexpr T operator -(T value) noexcept {
return value ^ f_traits<T>::sign_mask;
}
template<typename T, typename U, enable_when<is_alt_float<T>::value && is_alt_float<U>::value> = nullptr>
constexpr auto operator +(T l, U r) noexcept
-> decltype(cast<common_type_t<T, U>>(cast<typename f_traits<T>::f_type>(l) + cast<typename f_traits<U>::f_type>(r)))
{
using f1 = typename f_traits<T>::f_type;
using f2 = typename f_traits<U>::f_type;
return cast<common_type_t<T, U>>(cast<f1>(l) + cast<f2>(r));
}
template<typename T, typename U, enable_when<is_alt_float<T>::value && !is_alt_float<U>::value> = nullptr>
constexpr T operator +(T l, U r) noexcept(noexcept(cast<T>(r))) {
using f_type = typename f_traits<T>::f_type;
return cast<T>(cast<f_type>(l) + static_cast<f_type>(r));
}
template<typename T, typename U, enable_when<!is_alt_float<T>::value && is_alt_float<U>::value> = nullptr>
constexpr U operator +(T l, U r) noexcept(noexcept(r + l)) { return r + l; }
template<typename T, typename U, enable_when<is_alt_float<T>::value && is_alt_float<U>::value> = nullptr>
constexpr auto operator -(T l, U r) noexcept
-> decltype(cast<common_type_t<T, U>>(cast<typename f_traits<T>::f_type>(l) - cast<typename f_traits<U>::f_type>(r)))
{
using f1 = typename f_traits<T>::f_type;
using f2 = typename f_traits<U>::f_type;
return cast<common_type_t<T, U>>(cast<f1>(l) - cast<f2>(r));
}
template<typename T, typename U, enable_when<is_alt_float<T>::value && !is_alt_float<U>::value> = nullptr>
constexpr T operator -(T l, U r) noexcept(noexcept(cast<T>(r))) {
using f_type = typename f_traits<T>::f_type;
return cast<T>(cast<f_type>(l) - static_cast<f_type>(r));
}
template<typename T, typename U, enable_when<!is_alt_float<T>::value && is_alt_float<U>::value> = nullptr>
constexpr U operator -(T l, U r) noexcept(noexcept(cast<U>(l))) {
using f_type = typename f_traits<U>::f_type;
return cast<U>(static_cast<f_type>(l) - cast<f_type>(r));
}
template<typename T, typename U, enable_when<is_alt_float<T>::value && is_alt_float<U>::value> = nullptr>
constexpr auto operator *(T l, U r) noexcept
-> decltype(cast<common_type_t<T, U>>(cast<typename f_traits<T>::f_type>(l) * cast<typename f_traits<U>::f_type>(r)))
{
using f1 = typename f_traits<T>::f_type;
using f2 = typename f_traits<U>::f_type;
return cast<common_type_t<T, U>>(cast<f1>(l) * cast<f2>(r));
}
template<typename T, typename U, enable_when<is_alt_float<T>::value && !is_alt_float<U>::value> = nullptr>
constexpr T operator *(T l, U r) noexcept(noexcept(cast<T>(r))) {
using f_type = typename f_traits<T>::f_type;
return cast<T>(cast<f_type>(l) * static_cast<f_type>(r));
}
template<typename T, typename U, enable_when<!is_alt_float<T>::value && is_alt_float<U>::value> = nullptr>
constexpr U operator *(T l, U r) noexcept(noexcept(r * l)) { return r * l; }
template<typename T, typename U, enable_when<is_alt_float<T>::value && is_alt_float<U>::value> = nullptr>
constexpr auto operator /(T l, U r) noexcept
-> decltype(cast<common_type_t<T, U>>(cast<typename f_traits<T>::f_type>(l) / cast<typename f_traits<U>::f_type>(r)))
{
using f1 = typename f_traits<T>::f_type;
using f2 = typename f_traits<U>::f_type;
return cast<common_type_t<T, U>>(cast<f1>(l) / cast<f2>(r));
}
template<typename T, typename U, enable_when<is_alt_float<T>::value && !is_alt_float<U>::value> = nullptr>
constexpr T operator /(T l, U r) noexcept(noexcept(cast<T>(r))) {
using f_type = typename f_traits<T>::f_type;
return cast<T>(cast<f_type>(l) / static_cast<f_type>(r));
}
template<typename T, typename U, enable_when<!is_alt_float<T>::value && is_alt_float<U>::value> = nullptr>
constexpr U operator /(T l, U r) noexcept(noexcept(cast<U>(l))) {
using f_type = typename f_traits<U>::f_type;
return cast<U>(static_cast<f_type>(l) / cast<f_type>(r));
}
template<typename T, enable_when<is_alt_float<T>::value> = nullptr>
constexpr auto operator *(T value) noexcept
-> decltype(cast<typename f_traits<T>::f_type>(value))
{
return cast<typename f_traits<T>::f_type>(value);
}
}
}
#ifndef ALT_FLOAT_DEFINE_OSTREAM
# define ALT_FLOAT_DEFINE_OSTREAM 1
#endif
#if ALT_FLOAT_DEFINE_OSTREAM
# include <iostream>
namespace alt_float {
static inline std::ostream &operator<<(std::ostream &os, f32_t f)
{return os << *f; }
static inline std::ostream &operator<<(std::ostream &os, f64_t f)
{return os << *f; }
}
#endif
namespace alt_float {
inline namespace literal {
constexpr f32_t operator ""_f32(long double f) noexcept { return cast<f32_t>(f); }
constexpr f32_t operator ""_f32(unsigned long long f) noexcept { return cast<f32_t>(static_cast<long double>(f)); }
constexpr f64_t operator ""_f64(long double f) noexcept { return cast<f64_t>(f); }
constexpr f64_t operator ""_f64(unsigned long long f) noexcept { return cast<f64_t>(static_cast<long double>(f)); }
}
}
namespace af = alt_float;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment