「非型テンプレートパラメータに浮動小数点数を渡す方法」をC++11に移植してみた

https://qiita.com/kazatsuyu/items/1656e90b8ac0d999f12d をC++11環境でも使いたかったのでやってみた.

## 2019/03/27 追記

2の冪乗のとき `operator*` の結果が半分の値になるので現在修正中です.
従って, 現在の以下のコードは嘘がまぎれてます.

## 2019/03/27 追記2

修正. 凡ミス太郎...
`<` を `<=` にしてました...

## 2019/03/28 追記
オリジナルの作者の [kazatsuyu](https://qiita.com/kazatsuyu/) さんから公開の許可を頂いたのでCC0で取り敢えずgistに公開しました.
需要があるのか分かりませんが折角なのでC++11で使いたい方がいらっしゃれば.
https://gist.github.com/2bbb/254ed9627643c7359395b9155fe20c90

```cpp
// original source by kazatsuyu
// https://qiita.com/kazatsuyu/items/1656e90b8ac0d999f12d
// https://github.com/kazatsuyu

#include <type_traits>
#include <cstdint>
#include <cstddef>
#include <numeric>

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);
        }
    }
}

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)); }
    }
}
```

C++14って便利なんだなー...
ローカル変数は（負けた気分になりながら）マクロでなんとかするとしても, 複数の変数を書き換えるような `while` とかを外に出すとなると `constexpr`付きのコンストラクタを持った `std::pair` 的な何かを自分で書いてごにょごにょ...

取り敢えず動いたし良しとしよう.