【问题标题】:Is there a floating point literal suffix in C++ to make a number double precision?C++ 中是否有浮点文字后缀来使数字双精度?
【发布时间】:2012-08-30 20:41:02
【问题描述】:

我目前正在从事一个进行数值计算的 C++ 项目。绝大多数代码都使用单精度浮点值,并且可以很好地使用它。因此,我使用编译器标志来使基本浮点文字单精度而不是双精度,这是默认的。我发现这使表达式更易于阅读,而且我不必担心在某处忘记“f”。但是,我时不时需要双精度计算提供的额外精度,我的问题是如何将双精度文字放入这样的表达式中。到目前为止,我尝试过的每种方法都首先将值存储在单精度变量中,然后将截断的值转换为双精度值。不是我想要的。

下面给出了我目前尝试过的一些方法。

#include <iostream>

int main()
{
  std::cout << sizeof(1.0E200) << std::endl;
  std::cout << 1.0E200 << std::endl;

  std::cout << sizeof(1.0E200L) << std::endl;
  std::cout << 1.0E200L << std::endl;

  std::cout << sizeof(double(1.0E200)) << std::endl;
  std::cout << double(1.0E200) << std::endl;

  std::cout << sizeof(static_cast<double>(1.0E200)) << std::endl;
  std::cout << static_cast<double>(1.0E200) << std::endl;

  return 0;
}

使用单精度常量运行会产生以下结果。

~/path$ g++ test.cpp -fsingle-precision-constant && ./a.out
test.cpp:6:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:7:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:12:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:13:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:15:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
test.cpp:16:3: warning: floating constant exceeds range of ‘float’ [-Woverflow]
4
inf
16
1e+200
8
inf
8
inf

据我了解,最后两种情况提供的 8 个字节应该足以容纳 1.0E200,以下输出支持的理论,其中相同的程序在没有 -fsingle-precision-constant 的情况下编译。

~/path$ g++ test.cpp  && ./a.out
8
1e+200
16
1e+200
8
1e+200
8
1e+200

上述示例建议的一种可能的解决方法是在我最初打算使用双精度的任何地方使用四精度浮点文字,并在库等需要时转换为双精度。不过,这感觉有点浪费。

我还能做什么?

【问题讨论】:

  • 未尝试,但 strtod("1e+200") 可能会优化为您想要的双精度浮点常量。
  • 我不知道,这听起来有点像你在给自己制造问题。为什么不保持原样并将f 附加到不需要双精度的所有内容?
  • 你可以把你的双常量放在一个单独的文件中,并在没有-fsingle-precision-constant标志的情况下编译它。
  • 无论如何在全局范围内强制执行单精度常量有什么意义?
  • 好吧,你可以将“L”附加到浮点文字上,这表示“long double”——如果 ony 是迂腐的,这不一样,但它在每个我知道的编译器。

标签: c++ gcc precision literals


【解决方案1】:

就像 Mark 说的,标准说它是双精度的,除非它后面跟着一个 f。

标准背后有充分的理由,为了方便而使用编译器标志来绕过它是不好的做法。

所以,正确的做法是:

  1. 删除编译器标志
  2. 修复在浮点变量中存储双精度值时所有关于精度损失的警告(添加所有 f 后缀)
  3. 当您需要双精度时,请省略 f 后缀。

它可能不是您要寻找的答案,但如果您关心代码库的寿命,那么它是您应该使用的方法。

【讨论】:

  • 那些“好的理由”究竟是什么?它看起来更像是一个限制,使该特定标志难以使用。另外,使用double(1.0E200L) 有什么问题?这对寿命有何影响?
  • 代码库不应局限于特定的编译器。编译器应该符合标准。标准应该是唯一的事实来源。它会影响寿命,因为不符合标准会随着时间的推移引入不一致,因为各种程序员在代码库上工作并且每个人都以他们喜欢的方式做事。这就是标准存在的原因。
【解决方案2】:

如果您阅读 2.13.3/1,您会看到:

除非明确指定,否则浮动文字的类型是 double 通过后缀。后缀 f 和 F 指定浮点数,后缀 l 和 L 指定长双精度。

换句话说,如果将默认值更改为float,则没有为文字浮点常量指定double 的后缀。不幸的是,在这种情况下,您不能两全其美。

【讨论】:

  • 没关系,提问者在问题中提出了这个,发现它“浪费”。
【解决方案3】:

如果您负担得起 GCC 4.7 或 Clang 3.1,请使用用户定义的文字:

double operator "" _d(long double v) { return v; }

用法:

std::cout << sizeof(1.0E200_d) << std::endl;
std::cout << 1.0E200_d << std::endl;

结果:

8
1e+200

【讨论】:

    【解决方案4】:

    你不能定义你自己的后缀,但也许像一个宏

    #define D(x) (double(x##L))
    

    会为你工作。编译器应该只发出一个双精度常量,并在我的系统上显示为 -O2

    【讨论】:

    • +1 只是为了检查编译器是否发出一个双常量,当我对这个问题发表评论时说它会:-)
    猜你喜欢
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2016-06-24
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    相关资源
    最近更新 更多