【问题标题】:Why boost::geometry::distance with model::d2::point_xy<float> returns a double not a float?为什么 boost::geometry::distance 与 model::d2::point_xy<float> 返回一个双精度而不是浮点数?
【发布时间】:2015-05-01 07:50:02
【问题描述】:

我将 boost::geometry::distancemodel::d2::point_xy&lt;float&gt; 参数上的性能与等效的直接 2D 实现进行了比较:

struct Point {
  float x, y;
  float distance(const Point& p) const {return sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y));}
};

(请参阅http://rextester.com/NTOVR83857 的整个基准测试)。我发现 boost 版本在所有主要的 C++ 编译器中都比较慢:

  • gcc 为 1.77 倍
  • 1.47 倍铿锵声
  • vc++ 为 1.51 倍

我使用double 点坐标尝试了相同的基准测试,其中提升执行没有开销。我注意到带有model::d2::point_xy&lt;float&gt; 参数的boost::geometry::distance 返回double,这似乎是减速的原因。为什么它不返回float

【问题讨论】:

    标签: c++ performance boost boost-geometry


    【解决方案1】:

    由于 boost 使用的是模板,它需要确保返回类型具有足够的精度。想象一下,如果输入点具有 X 和 Y 的整数值 - 结果需要的不仅仅是整数精度。此外,如果输入 Point 对 X 和 Y 使用双精度值,float 的结果将不够精确。因此,似乎double 被选为具有足够精度的包罗万象。

    这里给出了设计距离模板的基本原理:

    http://www.boost.org/doc/libs/1_58_0/libs/geometry/doc/html/geometry/design.html

    【讨论】:

    • 我期望返回类型取决于参数类型:double 代表 model::d2::point_xy&lt;double&gt;float 代表 model::d2::point_xy&lt;float&gt; 等。distance_result&lt;G1, G2&gt;::type 不应该处理吗?
    • 如果是这样,那么它将为 model::d2::point_xy&lt;int&gt; 返回 int,这基本上是“损坏” - 精度太低。
    • 基本上被“破坏” - 精度太低 不一定,这取决于应用程序。此外,选择 double 作为默认值并不能为 64 位和更长的整数提供足够的精度。
    • 对于“通用”用法,double 被确定为“最合适”的返回类型。是的,它没有你的自制方法那么快。模板并不总是最适合每个人使用。不过我想你有你的答案。
    【解决方案2】:

    返回类型取决于策略:http://www.boost.org/doc/libs/1_58_0/libs/geometry/doc/html/geometry/design.html#geometry.design.return_type

    这让我觉得你可以通过策略明确指定计算类型:

    Live On Coliru

    #include <iostream>
    #include <boost/geometry/geometries/point_xy.hpp>
    #include <boost/geometry/algorithms/distance.hpp>
    #include <boost/geometry/strategies/distance.hpp>
    
    
    int main() {
        using namespace boost::geometry;
        using P = model::d2::point_xy<float>;
        using V = traits::coordinate_type<P>::type;
    
        std::cout << "Coordinate type:  " << typeid(V).name() << "\n";
    
        P a, b;
        std::cout << "Calculation type: " << typeid(default_distance_result<P, P>::calculation_type).name() << "\n";
        std::cout << "Result type:      " << typeid(default_distance_result<P, P>::type).name()             << "\n";
    
        using S = strategy::distance::pythagoras<V>;
        std::cout << "Calculation type: " << typeid(distance_result<P, P, S>::calculation_type).name() << "\n";
        std::cout << "Result type:      " << typeid(distance_result<P, P, S>::type).name()             << "\n";
    
        static_assert(boost::is_same<distance_result<P, P, S>::type, float>::value, "oops");
    }
    

    打印(通过c++filt -t 传送):

    Coordinate type:  float
    Calculation type: boost::geometry::strategy::distance::pythagoras<void>::calculation_type<boost::geometry::model::d2::point_xy<float, boost::geometry::cs::cartesian>, boost::geometry::model::d2::point_xy<float, boost::geometry::cs::cartesian> >
    Result type:      double
    Calculation type: boost::geometry::strategy::distance::pythagoras<float>::calculation_type<boost::geometry::model::d2::point_xy<float, boost::geometry::cs::cartesian>, boost::geometry::model::d2::point_xy<float, boost::geometry::cs::cartesian> >
    Result type:      float
    

    请注意,由于精度有限,结果精度可能会被截断。这在很大程度上是精度/存储效率的权衡。

    我实际上希望在任何地方使用double(而不是float)都能获得最佳性能,尤其是在对现代 CPU 指令集进行全面优化的情况下。

    【讨论】:

    • 你如何使用它来强制floatmodel::d2::point_xy&lt;float&gt;上返回distance
    • 我在代码中展示了!使用pythagoras&lt;float&gt; 策略...(请参阅我在底部添加的警告)
    • 我在代码中展示了它! 是的,你有,但我看不到。对于模板厌恶的观众来说,你的展示水平太高了。能否添加一行,实际上调用distance 并返回float
    • 我实际上预计最佳性能会出现在 double 无处不在这不会因为 double 的 2 倍带宽损失和浮点 SIMD 操作的 2 倍性能优势。跨度>
    • 哦,好吧。无论如何都要测量。我的印象是矢量化指令集偏爱双倍。我很可能是错的。另外,我没有考虑带宽瓶颈
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 2010-10-05
    • 1970-01-01
    相关资源
    最近更新 更多