考虑constexpr函数中的舍入模式

时间:2018-06-02 20:07:01

标签: c++ floating-point rounding

我正在尝试编写constexpr函数的exp版本。我知道

  • 我使用的算法专为FE_TONEAREST舍入
  • 而设计
  • 从C ++ 11开始,可以通过fesetround( int round )更改舍入模式(前提是支持#pragma STDC FENV_ACCESS且设置为ON
  • 我不允许在我自己的fesetround(int)函数中调用非constexpr函数constexpr

如果我的理解是正确的,这意味着(在支持#pragma STDC FENV_ACCESS的编译器中),允许用户在调用我的函数之前设置舍入模式,但是我的函数不会被允许做这个改变(甚至是暂时的),因此可以用错误的舍入模式来执行。

我可以提出处理此问题的最佳选择是拥有两个功能:

  • 版本A标记为constexpr,未设置舍入模式
  • 版本B 标记为constexpr并执行以下操作:
    1. 将舍入模式设置为FE_TONEAREST
    2. 致电版本A
    3. 重置舍入模式
    4. 返回版本A的结果

要设置一个constexpr变量,必须调用版本A,但总是会评估,因为舍入模式为FE_TONEAREST,因为(根据cppreference):< / p>

  

当前的舍入模式不会影响....的结果   常量表达式中的浮点算术运算符(总是为   最近的)

在非constexpr contexts中,只要舍入模式为FE_TONEAREST,版本A和版本B就会同意,但版本B将为任何其他舍入模式提供更好的结果。用户有责任使用FE_TONEAREST四舍五入确保调用版本B.

在标准C ++中是否有更好的方法来处理这个问题? ...或者该标准是否还有其他关于舍入模式的事情,这使得整个问题没有实际意义?

修改:我的目标是尊重舍入模式; 忽略,以便功能的准确性保持一致。我更愿意只使用版本B,但无法在constexpr函数中更改舍入模式。

1 个答案:

答案 0 :(得分:1)

C和C ++提供的FENV_ACCESS功能是一个kludge,并不支持在这个问题中寻求使用。修改舍入模式的程序很少,并且对它们的语言支持很差。

根据C标准(并通过引用由C ++继承),FENV_ACCESS通知实现程序可能在非默认浮点控制模式下运行。如果您允许在非默认模式下调用exp函数并且未使用FENV_ACCESS进行翻译,则标准不会告诉我们行为将是什么。

此外,C ++没有提供任何方法来根据舍入模式或FENV_ACCESS的状态自动调用不同版本的例程(尽管C ++实现可能会作为语言的扩展)

cppreference引用的语句,舍入模式不会影响常量表达式中的算术运算,这似乎是由cppreference派生的结论,而不是C ++标准中明确规定的结果。也许这是因为在转换时评估常量表达式,因此不能对浮点环境进行任何修改。但是,我不清楚这是否完全由标准保证 - expr.const部分中的注释说“在翻译期间可以评估常量表达式。”并不是说它们必须在翻译期间进行评估。

通常,当舍入模式最接近无限或其他设置时,人们不希望exp的行为方式相同。相反,当模式朝向无穷大时,人们希望exp返回向上舍入的结果,当模式朝向负无穷大时,需要向下舍入,当模式朝向零时,则向下舍入为零。 (获得这些结果需要为每种模式设置exp的不同实现,因为仅对每个操作应用舍入不会产生所需的结果。)因此,exp返回相同结果的请求无论如何舍入模式有点不寻常。当程序使用不同的舍入模式评估浮点运算时,它有什么作用来返回舍入到最接近的结果?如果程序使用朝向无穷大来尝试计算上限,则最接近的exp会破坏该计算。