C++ 现代C++;将常数双精度映射为整数的方法

C++ 现代C++;将常数双精度映射为整数的方法,c++,c++11,dictionary,C++,C++11,Dictionary,什么是将常量值加倍映射为整数的现代方法 我想这作为一个标题只包括 我避免了#define,而是从一堆if语句开始 我相信if语句速度更快(我对它们进行了优先级排序,并在其中添加了一些gotos),但下面的切换看起来更具可读性 我看了下面代码的分解,这似乎是合理的 我不喜欢这个巨大的开关。我认为可能有一种更好的现代方法(不损失性能或需要链接) inline int InchtoGauge(双d) { 开关(静态_型(d*10000)) { 判例2391:申报表3; 案例2242:返回4; 案例20

什么是将常量值加倍映射为整数的现代方法

我想这作为一个标题只包括

我避免了
#define
,而是从一堆
if
语句开始

我相信
if
语句速度更快(我对它们进行了优先级排序,并在其中添加了一些
goto
s),但下面的切换看起来更具可读性

我看了下面代码的分解,这似乎是合理的

我不喜欢这个巨大的开关。我认为可能有一种更好的现代方法(不损失性能或需要链接)

inline int InchtoGauge(双d)
{
开关(静态_型(d*10000))
{
判例2391:申报表3;
案例2242:返回4;
案例2092:返回5;
案例1943:返回6;
案例1793:返回7;
案例1644:返回8;
案例1495:返回9;
案例1345:返回10;
案例1196:申报表11;
案例1046:返回12;
判例897:返回13;
判例747:返回14;
案例673:返回15;
案例598:返回16;
案例538:返回17;
判例478:申报表18;
案例418:返回19;
案例359:返回20;
案例329:返回21;
判例299:返回22;
判例269:申报表23;
案例239:返回24;
案例209:返回25;
案例179:返回26;
案例164:返回27;
案例149:返回28;
案例135:返回29;
案例120:返回30;
案例105:返回31;
案例97:返回32;
案例90:返回33;
案例82:返回34;
案例75:返回35;
案例67:返回36;
默认值:return-1;
}
}

对您认为有问题的内容执行仅标题的实现是没有问题的

这里的主要问题是比较分数浮点值是否相等(代码显示您认为没有问题)

函数名
InchtoGauge
表明,命运多舛的比较只是一个简单函数的实现。你应该只计算这个函数。它看起来是这样的(您可以只对几个值进行插值):


顺便说一下,代码中的大量值显然是从5条直线段计算出来的。至少在我看来是这样的。这意味着您可以使用比现有值少得多的值来定义函数。

对您认为有问题的内容执行仅标题的实现是没有问题的

这里的主要问题是比较分数浮点值是否相等(代码显示您认为没有问题)

函数名
InchtoGauge
表明,命运多舛的比较只是一个简单函数的实现。你应该只计算这个函数。它看起来是这样的(您可以只对几个值进行插值):


顺便说一下,代码中的大量值显然是从5条直线段计算出来的。至少在我看来是这样的。这意味着您可以使用比现有值少得多的值来定义函数。

无论您实际希望如何使用数据,我认为最好先以某种简单、准确的形式存储数据:

static constexpr int GaugeToInchScale = 10000;
static constexpr std::array<int, 34> GaugeToInchScaledData = { 2391, 2242, ..., 67 };
static constexpr int GaugeToInchFirstGauge = 3;

无论您实际希望如何使用数据,我认为最好先以简单、准确的形式存储数据:

static constexpr int GaugeToInchScale = 10000;
static constexpr std::array<int, 34> GaugeToInchScaledData = { 2391, 2242, ..., 67 };
static constexpr int GaugeToInchFirstGauge = 3;

我比较了切换法、无序映射法和二进制搜索法 (我忽略了*10000)

intinchtogauge2(intd){
常量整数lut[]={
2391, 2242, 2092, 1943, 1793,
1644, 1495, 1345, 1196, 1046,...
};
常数int N=sizeof(lut)/sizeof(lut[0]);
const int n=下限(lut,lut+n,d,greater())-lut;
返回(n==n | | lut[n]!=d)?-1:3+n;
}
int InchtoGauge3(int d)
{
无序映射{
{2391, 3},
{2242, 4},
{2092, 5},...
};
自动p=m.find(d);
返回p==m.end()?-1:p->second;
}
我已经处决他们好几次了

  • 开关/外壳228us
  • 二进制搜索12913us
  • 无序地图1307857us
所以只要使用开关/外壳

已编辑

我尝试拆分cpp文件(以防止某些优化) 并使对象静止

差距仍然很大,但越来越小

运行时间:

  • 开关/外壳x
  • 二进制搜索15x
  • 无序地图25x

我比较了切换方法、无序映射和二进制搜索 (我忽略了*10000)

intinchtogauge2(intd){
常量整数lut[]={
2391, 2242, 2092, 1943, 1793,
1644, 1495, 1345, 1196, 1046,...
};
常数int N=sizeof(lut)/sizeof(lut[0]);
const int n=下限(lut,lut+n,d,greater())-lut;
返回(n==n | | lut[n]!=d)?-1:3+n;
}
int InchtoGauge3(int d)
{
无序映射{
{2391, 3},
{2242, 4},
{2092, 5},...
};
自动p=m.find(d);
返回p==m.end()?-1:p->second;
}
我已经处决他们好几次了

  • 开关/外壳228us
  • 二进制搜索12913us
  • 无序地图1307857us
所以只要使用开关/外壳

已编辑

我尝试拆分cpp文件(以防止某些优化) 并使对象静止

差距仍然很大,但越来越小

运行时间:

  • 开关/外壳x
  • 二进制搜索15x
  • 无序地图25x

将映射存储为排序数组,并使用二进制搜索执行查找(例如
std::lower_bound
)??关联数组、std::unordered_map或类似搜索。如果没有太多,我相信映射将是唯一的,没有冲突,它将执行得非常好。总比一个巨大的开关好。对于一个值数组,我建议使用数组。这里的主要问题是浮点值很少在相等时匹配。是否确实希望
InchtoGauge(0.1)
返回
-1
?将映射存储为
// searcher<N>::search(x) assumes `x` doesn't appear among the first `N` entries
template< int N >
struct searcher {
    constexpr static int search(int x) {
        if (x == GaugeToInchScaledData[N]) {
            return N + GaugeToInchFirstGauge;
        }
        return searcher<N+1>::search(x);
    }
};

template<>
struct searcher<GaugeToInchScaledData.size()>
{
    constexpr static int search(int x) {
        return -1;
    }
};

int search(int n) { return searcher<0>::search(n); }
int InchtoGauge2(int d) {
    const int lut[] = {
        2391, 2242, 2092, 1943, 1793,
        1644, 1495, 1345, 1196, 1046,...
    };
    const int N = sizeof(lut)/sizeof(lut[0]);
    const int n = lower_bound(lut, lut+N, d, greater<int>()) - lut;
    return (n==N || lut[n]!=d)? -1: 3+n;
}

int InchtoGauge3(int d)
{
    unordered_map<int,int> m{
        {2391, 3},
        {2242, 4},
        {2092, 5},...
    };
    auto p = m.find(d);
    return p == m.end()? -1: p->second;
}