Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 编译时浮点初始化的替代方法_C++_Templates_C++11_Floating Point_Template Meta Programming - Fatal编程技术网

C++ 编译时浮点初始化的替代方法

C++ 编译时浮点初始化的替代方法,c++,templates,c++11,floating-point,template-meta-programming,C++,Templates,C++11,Floating Point,Template Meta Programming,我目前正在做一个基于模板元编程的浮点算法实现。表示编译时浮点值的模板如下所示: template<bool S , std::int16_t E , std::uint64_t M> struct number{}; tml是库的主要名称空间,浮点特性在tml::floating名称空间中公开 TL;博士 tml::eval接受任何表达式并对其求值,返回其值。它是一个C++11模板别名,因此不需要typename::type tml::integral_constant(只是st

我目前正在做一个基于模板元编程的浮点算法实现。表示编译时浮点值的模板如下所示:

template<bool S , std::int16_t E , std::uint64_t M>
struct number{};
tml
是库的主要名称空间,浮点特性在
tml::floating
名称空间中公开

TL;博士
  • tml::eval
    接受任何表达式并对其求值,返回其值。它是一个C++11模板别名,因此不需要
    typename::type

  • tml::integral_constant
    (只是
    std::integral_constant
    的别名)是通过装箱将值参数作为类型参数传递的事实上的值包装器。该库具有仅使用类型参数的约定(模板参数也有包装器,请参见和)

尝试1:从整数开始 这里我们定义了一个元函数
integer
,它从整数返回一个浮点值:

template<std::int64_t mantissa , sign_t S = (sign_t)(mantissa >= 0)>
struct integer
{
    using m   = tml::floating::number<S,0,static_cast<mantissa_t>((mantissa >= 0) ? mantissa : -mantissa)>;
    using hsb = tml::floating::highest_set_bit<m>;
    static constexpr const exponent_t exp = hsb::value - 31;

    using result = tml::floating::number<S,exp,(m::mantissa << (31 - hsb::value))>; //Note the number is normalized
};
它所做的是计算整数部分的值(只需调用前面的
integer
)和小数部分的值。
小数部分的值是调整后的整数值,直到小数点位于数字的开头。换言之:

                       integer<fractional_part>
fractional_value = ________________________________
                          10^number_of_digits
整数的位数为
log10(number)+1
。我最终得到了一个不需要递归的整数值的
log10
元函数:

template<typename N>
struct log10
{
    using result = tml::Int<(0  <= N::value && N::value < 10)  ? 0 :
                            (10 <= N::value && N::value < 100) ? 1 :
                            ...
                           >;
} 
要计算该数字,只需取有效值乘以相应的10次方:

template<std::int64_t S , std::int64_t E>
struct decimal_sci
{
    using significant = tml::floating::integer<S>;
    using power       = tml::eval<tml::pow<tml::floating::integer<10>,tml::Int<E>>>;

    using result = tml::eval<tml::mul<significant,power>>;
};
优势
  • 以一种简单的方式使用宽编号的潜在客户,包括标题零
  • 使用一个众所周知的符号,不涉及语法技巧
缺点
  • 非常大/小的数字精度很差(这是预期的,因为科学记数法就是这样工作的)。注意:浮点内部计算可能导致累积精度误差,与(尾数的)长度和数字的指数成正比。与上述尝试的精度错误相同(使用
    tml::pow
    tml::div
    等)

您可能希望使用用户定义的文本。据cppreference.com称

允许整数、浮点、字符和字符串文字通过定义用户定义的 后缀

(另见)。通过这种方式,您可以创建表达式

123.456_mysuffix
如果为_mysuffix定义文字运算符,则可以生成所需的任何类型。使用该运算符,您可以访问输入123.456作为(标准c++)浮点数,也可以自己从原始字符串作为常量字符*进行必要的转换


编辑:在阅读了您编辑的问题并了解了您所谈论的模板元编程类型之后,我只想强调,文本也可以作为
char
模板参数的参数包访问。您可以将其集成到编译时框架中。

科学符号不是更合适吗?也就是说,将第一个模板整数视为在第一个非零数字后有一个小数点,而将另一个参数视为十进制指数?因此,
decimal
对应于
1.23e4
?@Ben decimal科学记数法,谢谢!当我问这个问题时,我完全忘记了这一点:(.这可能是另一种选择(如果你愿意,写一个答案),但我想问更多关于自然(十进制)初始化的问题像
123.33
。标准库中存在类似的东西,只是它不是“小数”,而是“有理数”,即
std::ratio
。它是
std::ratio
。如果这不是一个选项,我认为
decimal
将是表示
123.33
@Rapptz:“我认为十进制是表示123.33的好方法“-这个问题正是关于这种方法的问题,例如您如何表示
123.033
-0.1
?@MichaelBurr确切地说,这个问题是关于浮点初始化的不同方法,以及它们的优缺点。我有5种不同的方法(整数初始化、十进制初始化
decimal
、十进制科学记数法、规范化十进制科学记数法,最后是通过用户定义的文字和解析元函数解析浮点文字)在这个时候实现了,我的想法是将所有这些都包含在问题的“调度解决方案”部分。谢谢,我最终这样做了,除了一个宏
#FOLAT(x)decltype(x#mysuffix)
。正如您在编辑中注意到的,它最终是字符串(字符包)中的数字。很酷,很高兴它有帮助!
                       integer<fractional_part>
fractional_value = ________________________________
                          10^number_of_digits
result = integer_part_value + fractional_value
template<typename N>
struct log10
{
    using result = tml::Int<(0  <= N::value && N::value < 10)  ? 0 :
                            (10 <= N::value && N::value < 100) ? 1 :
                            ...
                           >;
} 
//First some aliases, to make the code more handy:
using integral_i   = tml::integral_constant<std::int64_t,INTEGRAL>;
using integral_f   = tml::floating::integer<INTEGRAL>;
using fractional_f = tml::floating::integer<FRACTIONAL>;
using ten          = tml::floating::integer<10>;
using one          = tml::Int<1>;

using fractional_value = tml::eval<tml::div<fractional_f , 
                                            tml::pow<ten,
                                                     tml::add<tml::log10<integral_i>,
                                                              one
                                                             >
                                                    >
                                           >
                                  > 
 using result = tml::eval<tml::add<integral_f,fractional_value>>;
using pi = tml::floating::decimal_sci<3141592654,-9>; //3141592654 x 10^-9
template<std::int64_t S , std::int64_t E>
struct decimal_sci
{
    using significant = tml::floating::integer<S>;
    using power       = tml::eval<tml::pow<tml::floating::integer<10>,tml::Int<E>>>;

    using result = tml::eval<tml::mul<significant,power>>;
};
template<std::int64_t S , std::int64_t E = 0>
struct decimal_scinorm
{
    using significant_i = tml::integral_constant<std::int64_t,S>;
    using exponent_i    = tml::integral_constant<std::int64_t,E>;

    using adjust  = tml::eval<tml::log10<significant_i>>;
    using new_exp = tml::eval<tml::sub<exponent_i,adjust>>;

    using result = typename decimal_sci<S,new_exp::value>::result;
};

using pi = tml::floating::decimal_scinorm<3141592654>; //3.141592654
using i  = tml::floating::decimal_scinorm<999999,-4>;  //0.000999999
123.456_mysuffix