什么是基于输入编程输出的最有效方法(目前使用大量的if语句完成)?

时间:2017-07-16 09:19:24

标签: performance comparison microcontroller

在操作期间的微控制器float output_value将给出不同的值(控制算法)。我想利用某种“查找表”,在其中我比较从float output_value找到float final_output_value的每个值。

我现在有很多if语句,例如:

if(output_value > 3.0 && output_value < 5.0)
{
 final_output_value = 3.2;
} 
if(output_value > 5.0 && output_value < 8.0)
{
 final_output_value = 5.7
} 

这就是这个想法。我正在寻找一种更有效的方式,有人知道更好的方法吗?

1 个答案:

答案 0 :(得分:1)

这里有许多决定因素你不提,所以让我概述一下:

  • 可维护性(即,使代码正确并维护代码是多么容易)
  • 波动率(即,范围值及其输出的变化频率是多少?)
  • 代码大小(您提到微控制器场景,您是否需要克服代码大小的限制?)

我有一个额外的问题可能会改变我给出的建议(我说这是因为我只测试了一个变体,我不知道另一个的影响)是否可以优化范围检查。

你有这两个:

3.0 < v < 5.0
5.0 < v < 8.0

但5.0 完全 呢?

你可以改写这样的范围:

3.0 <= v < 5.0
5.0 <= v < 8.0

(或将等号放在另一个上),这样范围是连续的,没有空洞?我假设是的,你可以。

无论如何,我所做的是:

  1. 写一个纯粹的&#34;线性&#34;基于代码的if语句集,其中300个
  2. 编写一个表驱动的方法,通过从第1点调用方法,构建一个表,然后重复使用该表在每个lookoup上进行二进制搜索
  3. 从第1点开始编写稍微好一点的基于代码的方法。
  4. 基本上,&#34;线性&#34;代码方法看起来像这样:

    private double IfStatementLookup(double input)
    {
        if (input < 01.0) return 01.0;
        if (input < 02.0) return 02.0;
        if (input < 03.0) return 03.0;
        if (input < 04.0) return 04.0;
        if (input < 05.0) return 05.0;
    

    依此类推< 300,基本上是一个简单的&#34;天花板&#34;函数表示一组值。因此0 <= input < 1会返回1,依此类推。

    表驱动的方法如下所示:

    private double TableLookup(double input)
    {
        if (input >= 300)
            return 0;
    
        int lower = 0;
        int upper = _Table.Length - 1;
    
        while (lower <= upper)
        {
            int middle = lower + (upper - lower) / 2;
            if (input < _Table[middle][0])
                upper = middle - 1;
            else
                lower = middle + 1;
        }
    
        return _Table[upper][1];
    }
    

    if语句稍微好一点的版本如下:

    double SlightlyOptimizedIfStatementLookup(double input)
    {
        if (input < 100)
        {
            if (input < 50)
            {
                if (input < 01.0) return 01.0;
                if (input < 02.0) return 02.0;
                if (input < 03.0) return 03.0;
            }
            // if-statements for 50-100
        }
        if (input < 200)
            // same here for 200-299
        if (input < 300)
            // same here for 300-399
    

    现在,在我展示基准测试结果之前,这里有一些要点:

    1. if语句方法可能需要比表驱动方法更多的代码,因此您需要考虑这是否非常重要
    2. 通过大致将每个新级别的if语句的范围减半,例如通过为< 25< 75添加if语句,可以进一步更改if语句稍微好一点的版本在各个层面内等等
    3. if语句方法(任一方法)不是运行时可维护的。您无法动态加载文件范围表,或通过用户界面或下载此类表进行维护,您需要发布新版本的软件才能对其进行更改。
    4. 也可以对表驱动方法进行进一步优化。
    5. 可以在此答案的底部找到整个LINQPad程序。请务必在启用优化的情况下运行它(右下方的/o+小按钮)。

      CAVEAT!我可能在程序中犯了许多错误,这些错误有可能使我的整个答案无效。请单独验证结果。

      在任何情况下,这里都是缩写的基准测试结果:

                              Method |      Mean |     Error |    StdDev |
      ------------------------------ |----------:|----------:|----------:|
                         TableDriven | 163.95 us | 0.9125 us | 0.7620 us |
                  LinearIfStatements | 314.41 us | 2.3511 us | 2.0842 us |
       SlightlyOptimizedIfStatements |  64.43 us | 0.7900 us | 0.7390 us |
      

      结论:基于代码的基于if语句的方法优于(我的简单)表驱动方法。

      这是整个程序,请注意由于if语句的数量有点长。

      void Main()
      {
          new LookupTest().Validate();
          BenchmarkRunner.Run<LookupTest>();
      }
      
      public class LookupTest
      {
          public LookupTest()
          {
              _Inputs = Enumerable.Range(0, 3000).Select(idx => idx / 10.0).ToArray();
              _Table = _Inputs.Select(input => new[] { input, IfStatementLookup(input) }).ToArray();
      
              TableDriven();
          }
      
          public void Validate()
          {
              bool anyMismatch = false;
              foreach (var input in _Inputs)
              {
                  var ifStatements = IfStatementLookup(input);
                  var slightlyOptimizedIfStatements = SlightlyOptimizedIfStatementLookup(input);
                  var tableDriven = TableLookup(input);
      
                  if (ifStatements != tableDriven || ifStatements != slightlyOptimizedIfStatements)
                  {
                      $"{input:0.00} => if: {ifStatements}, lookup: {tableDriven}, if+: {slightlyOptimizedIfStatements}".Dump();
                      anyMismatch = true;
                  }
              }
              if (anyMismatch)
                  throw new InvalidOperationException();
          }
      
          private double[] _Inputs;
          private double[][] _Table;
      
          [Benchmark]
          public void TableDriven()
          {
              double sum = 0;
              for (int index = 0; index < _Inputs.Length; index++)
              {
                  sum += TableLookup(_Inputs[index]);
              }
              if (sum < 0)
                  throw new InvalidOperationException();
          }
      
          private double TableLookup(double input)
          {
              if (input >= 300)
                  return 0;
      
              int lower = 0;
              int upper = _Table.Length - 1;
      
              while (lower <= upper)
              {
                  int middle = lower + (upper - lower) / 2;
                  if (input < _Table[middle][0])
                      upper = middle - 1;
                  else
                      lower = middle + 1;
              }
      
              return _Table[upper][1];
          }
      
          [Benchmark]
          public void LinearIfStatements()
          {
              double sum = 0;
              for (int index = 0; index < _Inputs.Length; index++)
              {
                  sum += IfStatementLookup(_Inputs[index]);
              }
              if (sum < 0)
                  throw new InvalidOperationException();
          }
      
          [Benchmark]
          public void SlightlyOptimizedIfStatements()
          {
              double sum = 0;
              for (int index = 0; index < _Inputs.Length; index++)
              {
                  sum += SlightlyOptimizedIfStatementLookup(_Inputs[index]);
              }
              if (sum < 0)
                  throw new InvalidOperationException();
          }
      
          private double IfStatementLookup(double input)
          {
              if (input < 01.0) return 01.0;
              if (input < 02.0) return 02.0;
              if (input < 03.0) return 03.0;
              if (input < 04.0) return 04.0;
              if (input < 05.0) return 05.0;
              if (input < 06.0) return 06.0;
              if (input < 07.0) return 07.0;
              if (input < 08.0) return 08.0;
              if (input < 09.0) return 09.0;
              if (input < 10.0) return 10.0;
              if (input < 11.0) return 11.0;
              if (input < 12.0) return 12.0;
              if (input < 13.0) return 13.0;
              if (input < 14.0) return 14.0;
              if (input < 15.0) return 15.0;
              if (input < 16.0) return 16.0;
              if (input < 17.0) return 17.0;
              if (input < 18.0) return 18.0;
              if (input < 19.0) return 19.0;
              if (input < 20.0) return 20.0;
              if (input < 21.0) return 21.0;
              if (input < 22.0) return 22.0;
              if (input < 23.0) return 23.0;
              if (input < 24.0) return 24.0;
              if (input < 25.0) return 25.0;
              if (input < 26.0) return 26.0;
              if (input < 27.0) return 27.0;
              if (input < 28.0) return 28.0;
              if (input < 29.0) return 29.0;
              if (input < 30.0) return 30.0;
              if (input < 31.0) return 31.0;
              if (input < 32.0) return 32.0;
              if (input < 33.0) return 33.0;
              if (input < 34.0) return 34.0;
              if (input < 35.0) return 35.0;
              if (input < 36.0) return 36.0;
              if (input < 37.0) return 37.0;
              if (input < 38.0) return 38.0;
              if (input < 39.0) return 39.0;
              if (input < 40.0) return 40.0;
              if (input < 41.0) return 41.0;
              if (input < 42.0) return 42.0;
              if (input < 43.0) return 43.0;
              if (input < 44.0) return 44.0;
              if (input < 45.0) return 45.0;
              if (input < 46.0) return 46.0;
              if (input < 47.0) return 47.0;
              if (input < 48.0) return 48.0;
              if (input < 49.0) return 49.0;
              if (input < 50.0) return 50.0;
              if (input < 51.0) return 51.0;
              if (input < 52.0) return 52.0;
              if (input < 53.0) return 53.0;
              if (input < 54.0) return 54.0;
              if (input < 55.0) return 55.0;
              if (input < 56.0) return 56.0;
              if (input < 57.0) return 57.0;
              if (input < 58.0) return 58.0;
              if (input < 59.0) return 59.0;
              if (input < 60.0) return 60.0;
              if (input < 61.0) return 61.0;
              if (input < 62.0) return 62.0;
              if (input < 63.0) return 63.0;
              if (input < 64.0) return 64.0;
              if (input < 65.0) return 65.0;
              if (input < 66.0) return 66.0;
              if (input < 67.0) return 67.0;
              if (input < 68.0) return 68.0;
              if (input < 69.0) return 69.0;
              if (input < 70.0) return 70.0;
              if (input < 71.0) return 71.0;
              if (input < 72.0) return 72.0;
              if (input < 73.0) return 73.0;
              if (input < 74.0) return 74.0;
              if (input < 75.0) return 75.0;
              if (input < 76.0) return 76.0;
              if (input < 77.0) return 77.0;
              if (input < 78.0) return 78.0;
              if (input < 79.0) return 79.0;
              if (input < 80.0) return 80.0;
              if (input < 81.0) return 81.0;
              if (input < 82.0) return 82.0;
              if (input < 83.0) return 83.0;
              if (input < 84.0) return 84.0;
              if (input < 85.0) return 85.0;
              if (input < 86.0) return 86.0;
              if (input < 87.0) return 87.0;
              if (input < 88.0) return 88.0;
              if (input < 89.0) return 89.0;
              if (input < 90.0) return 90.0;
              if (input < 91.0) return 91.0;
              if (input < 92.0) return 92.0;
              if (input < 93.0) return 93.0;
              if (input < 94.0) return 94.0;
              if (input < 95.0) return 95.0;
              if (input < 96.0) return 96.0;
              if (input < 97.0) return 97.0;
              if (input < 98.0) return 98.0;
              if (input < 99.0) return 99.0;
              if (input < 100.0) return 100.0;
              if (input < 101.0) return 101.0;
              if (input < 102.0) return 102.0;
              if (input < 103.0) return 103.0;
              if (input < 104.0) return 104.0;
              if (input < 105.0) return 105.0;
              if (input < 106.0) return 106.0;
              if (input < 107.0) return 107.0;
              if (input < 108.0) return 108.0;
              if (input < 109.0) return 109.0;
              if (input < 110.0) return 110.0;
              if (input < 111.0) return 111.0;
              if (input < 112.0) return 112.0;
              if (input < 113.0) return 113.0;
              if (input < 114.0) return 114.0;
              if (input < 115.0) return 115.0;
              if (input < 116.0) return 116.0;
              if (input < 117.0) return 117.0;
              if (input < 118.0) return 118.0;
              if (input < 119.0) return 119.0;
              if (input < 120.0) return 120.0;
              if (input < 121.0) return 121.0;
              if (input < 122.0) return 122.0;
              if (input < 123.0) return 123.0;
              if (input < 124.0) return 124.0;
              if (input < 125.0) return 125.0;
              if (input < 126.0) return 126.0;
              if (input < 127.0) return 127.0;
              if (input < 128.0) return 128.0;
              if (input < 129.0) return 129.0;
              if (input < 130.0) return 130.0;
              if (input < 131.0) return 131.0;
              if (input < 132.0) return 132.0;
              if (input < 133.0) return 133.0;
              if (input < 134.0) return 134.0;
              if (input < 135.0) return 135.0;
              if (input < 136.0) return 136.0;
              if (input < 137.0) return 137.0;
              if (input < 138.0) return 138.0;
              if (input < 139.0) return 139.0;
              if (input < 140.0) return 140.0;
              if (input < 141.0) return 141.0;
              if (input < 142.0) return 142.0;
              if (input < 143.0) return 143.0;
              if (input < 144.0) return 144.0;
              if (input < 145.0) return 145.0;
              if (input < 146.0) return 146.0;
              if (input < 147.0) return 147.0;
              if (input < 148.0) return 148.0;
              if (input < 149.0) return 149.0;
              if (input < 150.0) return 150.0;
              if (input < 151.0) return 151.0;
              if (input < 152.0) return 152.0;
              if (input < 153.0) return 153.0;
              if (input < 154.0) return 154.0;
              if (input < 155.0) return 155.0;
              if (input < 156.0) return 156.0;
              if (input < 157.0) return 157.0;
              if (input < 158.0) return 158.0;
              if (input < 159.0) return 159.0;
              if (input < 160.0) return 160.0;
              if (input < 161.0) return 161.0;
              if (input < 162.0) return 162.0;
              if (input < 163.0) return 163.0;
              if (input < 164.0) return 164.0;
              if (input < 165.0) return 165.0;
              if (input < 166.0) return 166.0;
              if (input < 167.0) return 167.0;
              if (input < 168.0) return 168.0;
              if (input < 169.0) return 169.0;
              if (input < 170.0) return 170.0;
              if (input < 171.0) return 171.0;
              if (input < 172.0) return 172.0;
              if (input < 173.0) return 173.0;
              if (input < 174.0) return 174.0;
              if (input < 175.0) return 175.0;
              if (input < 176.0) return 176.0;
              if (input < 177.0) return 177.0;
              if (input < 178.0) return 178.0;
              if (input < 179.0) return 179.0;
              if (input < 180.0) return 180.0;
              if (input < 181.0) return 181.0;
              if (input < 182.0) return 182.0;
              if (input < 183.0) return 183.0;
              if (input < 184.0) return 184.0;
              if (input < 185.0) return 185.0;
              if (input < 186.0) return 186.0;
              if (input < 187.0) return 187.0;
              if (input < 188.0) return 188.0;
              if (input < 189.0) return 189.0;
              if (input < 190.0) return 190.0;
              if (input < 191.0) return 191.0;
              if (input < 192.0) return 192.0;
              if (input < 193.0) return 193.0;
              if (input < 194.0) return 194.0;
              if (input < 195.0) return 195.0;
              if (input < 196.0) return 196.0;
              if (input < 197.0) return 197.0;
              if (input < 198.0) return 198.0;
              if (input < 199.0) return 199.0;
      
              # error Stack Overflow limited my answer
              // Copy the 200-299-block above and just
              // Alt+Shift Selection to mark the 2's and change them to 3's
              // BOTH PLACES
      
              return 0;
          }
      
          double SlightlyOptimizedIfStatementLookup(double input)
          {
              if (input < 100)
              {
                  if (input < 50)
                  {
                      if (input < 01.0) return 01.0;
                      if (input < 02.0) return 02.0;
                      if (input < 03.0) return 03.0;
                      if (input < 04.0) return 04.0;
                      if (input < 05.0) return 05.0;
                      if (input < 06.0) return 06.0;
                      if (input < 07.0) return 07.0;
                      if (input < 08.0) return 08.0;
                      if (input < 09.0) return 09.0;
                      if (input < 10.0) return 10.0;
                      if (input < 11.0) return 11.0;
                      if (input < 12.0) return 12.0;
                      if (input < 13.0) return 13.0;
                      if (input < 14.0) return 14.0;
                      if (input < 15.0) return 15.0;
                      if (input < 16.0) return 16.0;
                      if (input < 17.0) return 17.0;
                      if (input < 18.0) return 18.0;
                      if (input < 19.0) return 19.0;
                      if (input < 20.0) return 20.0;
                      if (input < 21.0) return 21.0;
                      if (input < 22.0) return 22.0;
                      if (input < 23.0) return 23.0;
                      if (input < 24.0) return 24.0;
                      if (input < 25.0) return 25.0;
                      if (input < 26.0) return 26.0;
                      if (input < 27.0) return 27.0;
                      if (input < 28.0) return 28.0;
                      if (input < 29.0) return 29.0;
                      if (input < 30.0) return 30.0;
                      if (input < 31.0) return 31.0;
                      if (input < 32.0) return 32.0;
                      if (input < 33.0) return 33.0;
                      if (input < 34.0) return 34.0;
                      if (input < 35.0) return 35.0;
                      if (input < 36.0) return 36.0;
                      if (input < 37.0) return 37.0;
                      if (input < 38.0) return 38.0;
                      if (input < 39.0) return 39.0;
                      if (input < 40.0) return 40.0;
                      if (input < 41.0) return 41.0;
                      if (input < 42.0) return 42.0;
                      if (input < 43.0) return 43.0;
                      if (input < 44.0) return 44.0;
                      if (input < 45.0) return 45.0;
                      if (input < 46.0) return 46.0;
                      if (input < 47.0) return 47.0;
                      if (input < 48.0) return 48.0;
                      if (input < 49.0) return 49.0;
                      return 50.0;
                  }
      
                  if (input < 51.0) return 51.0;
                  if (input < 52.0) return 52.0;
                  if (input < 53.0) return 53.0;
                  if (input < 54.0) return 54.0;
                  if (input < 55.0) return 55.0;
                  if (input < 56.0) return 56.0;
                  if (input < 57.0) return 57.0;
                  if (input < 58.0) return 58.0;
                  if (input < 59.0) return 59.0;
                  if (input < 60.0) return 60.0;
                  if (input < 61.0) return 61.0;
                  if (input < 62.0) return 62.0;
                  if (input < 63.0) return 63.0;
                  if (input < 64.0) return 64.0;
                  if (input < 65.0) return 65.0;
                  if (input < 66.0) return 66.0;
                  if (input < 67.0) return 67.0;
                  if (input < 68.0) return 68.0;
                  if (input < 69.0) return 69.0;
                  if (input < 70.0) return 70.0;
                  if (input < 71.0) return 71.0;
                  if (input < 72.0) return 72.0;
                  if (input < 73.0) return 73.0;
                  if (input < 74.0) return 74.0;
                  if (input < 75.0) return 75.0;
                  if (input < 76.0) return 76.0;
                  if (input < 77.0) return 77.0;
                  if (input < 78.0) return 78.0;
                  if (input < 79.0) return 79.0;
                  if (input < 80.0) return 80.0;
                  if (input < 81.0) return 81.0;
                  if (input < 82.0) return 82.0;
                  if (input < 83.0) return 83.0;
                  if (input < 84.0) return 84.0;
                  if (input < 85.0) return 85.0;
                  if (input < 86.0) return 86.0;
                  if (input < 87.0) return 87.0;
                  if (input < 88.0) return 88.0;
                  if (input < 89.0) return 89.0;
                  if (input < 90.0) return 90.0;
                  if (input < 91.0) return 91.0;
                  if (input < 92.0) return 92.0;
                  if (input < 93.0) return 93.0;
                  if (input < 94.0) return 94.0;
                  if (input < 95.0) return 95.0;
                  if (input < 96.0) return 96.0;
                  if (input < 97.0) return 97.0;
                  if (input < 98.0) return 98.0;
                  if (input < 99.0) return 99.0;
                  return 100.0;
              }
              if (input < 200)
              {
                  if (input < 150)
                  {
                      if (input < 101.0) return 101.0;
                      if (input < 102.0) return 102.0;
                      if (input < 103.0) return 103.0;
                      if (input < 104.0) return 104.0;
                      if (input < 105.0) return 105.0;
                      if (input < 106.0) return 106.0;
                      if (input < 107.0) return 107.0;
                      if (input < 108.0) return 108.0;
                      if (input < 109.0) return 109.0;
                      if (input < 110.0) return 110.0;
                      if (input < 111.0) return 111.0;
                      if (input < 112.0) return 112.0;
                      if (input < 113.0) return 113.0;
                      if (input < 114.0) return 114.0;
                      if (input < 115.0) return 115.0;
                      if (input < 116.0) return 116.0;
                      if (input < 117.0) return 117.0;
                      if (input < 118.0) return 118.0;
                      if (input < 119.0) return 119.0;
                      if (input < 120.0) return 120.0;
                      if (input < 121.0) return 121.0;
                      if (input < 122.0) return 122.0;
                      if (input < 123.0) return 123.0;
                      if (input < 124.0) return 124.0;
                      if (input < 125.0) return 125.0;
                      if (input < 126.0) return 126.0;
                      if (input < 127.0) return 127.0;
                      if (input < 128.0) return 128.0;
                      if (input < 129.0) return 129.0;
                      if (input < 130.0) return 130.0;
                      if (input < 131.0) return 131.0;
                      if (input < 132.0) return 132.0;
                      if (input < 133.0) return 133.0;
                      if (input < 134.0) return 134.0;
                      if (input < 135.0) return 135.0;
                      if (input < 136.0) return 136.0;
                      if (input < 137.0) return 137.0;
                      if (input < 138.0) return 138.0;
                      if (input < 139.0) return 139.0;
                      if (input < 140.0) return 140.0;
                      if (input < 141.0) return 141.0;
                      if (input < 142.0) return 142.0;
                      if (input < 143.0) return 143.0;
                      if (input < 144.0) return 144.0;
                      if (input < 145.0) return 145.0;
                      if (input < 146.0) return 146.0;
                      if (input < 147.0) return 147.0;
                      if (input < 148.0) return 148.0;
                      if (input < 149.0) return 149.0;
                      return 150.0;
                  }
                  if (input < 151.0) return 151.0;
                  if (input < 152.0) return 152.0;
                  if (input < 153.0) return 153.0;
                  if (input < 154.0) return 154.0;
                  if (input < 155.0) return 155.0;
                  if (input < 156.0) return 156.0;
                  if (input < 157.0) return 157.0;
                  if (input < 158.0) return 158.0;
                  if (input < 159.0) return 159.0;
                  if (input < 160.0) return 160.0;
                  if (input < 161.0) return 161.0;
                  if (input < 162.0) return 162.0;
                  if (input < 163.0) return 163.0;
                  if (input < 164.0) return 164.0;
                  if (input < 165.0) return 165.0;
                  if (input < 166.0) return 166.0;
                  if (input < 167.0) return 167.0;
                  if (input < 168.0) return 168.0;
                  if (input < 169.0) return 169.0;
                  if (input < 170.0) return 170.0;
                  if (input < 171.0) return 171.0;
                  if (input < 172.0) return 172.0;
                  if (input < 173.0) return 173.0;
                  if (input < 174.0) return 174.0;
                  if (input < 175.0) return 175.0;
                  if (input < 176.0) return 176.0;
                  if (input < 177.0) return 177.0;
                  if (input < 178.0) return 178.0;
                  if (input < 179.0) return 179.0;
                  if (input < 180.0) return 180.0;
                  if (input < 181.0) return 181.0;
                  if (input < 182.0) return 182.0;
                  if (input < 183.0) return 183.0;
                  if (input < 184.0) return 184.0;
                  if (input < 185.0) return 185.0;
                  if (input < 186.0) return 186.0;
                  if (input < 187.0) return 187.0;
                  if (input < 188.0) return 188.0;
                  if (input < 189.0) return 189.0;
                  if (input < 190.0) return 190.0;
                  if (input < 191.0) return 191.0;
                  if (input < 192.0) return 192.0;
                  if (input < 193.0) return 193.0;
                  if (input < 194.0) return 194.0;
                  if (input < 195.0) return 195.0;
                  if (input < 196.0) return 196.0;
                  if (input < 197.0) return 197.0;
                  if (input < 198.0) return 198.0;
                  if (input < 199.0) return 199.0;
                  return 200.0;
              }
              if (input < 300)
              {
                  # error Stack Overflow limited my answer
                  // Copy the 200-block above and just
                  // Alt+Shift Selection to mark the 2's and change them to 3's
                  // BOTH PLACES
              }
              return 0;
          }
      }
      

      由于Stack Overflow限制为30.000个字符,我不得不缩短上面的程序。您可以下载完整的LINQPad脚本here