2015-11-06 28 views
1

我有这样的功能:我可以加快我的特殊轮功能吗?

int round(double val) { 
    if (val >= 0) { 
     return (int)Math.Floor(val + 0.5); 
    } 
    return (int)Math.Ceiling(val - 0.5); 
} 

我把它在我的计划中有许多次,我的意思是很多次,所以它的每一个milisecond的运行时间的问题。有没有比现在更快的方法? THX

编辑:

的功能是用于在图像中计算的线的切线方向的算法的一部分。它来自学术文章。由于它以弧度值处理角度,因此它使用小而精确的数字。

I/O的例子:

0 -> 0 
1 -> 1 
1.1 -> 1 
1.51 -> 2 
-0.1 -> 0 
-1 -> -1 
-1.1 -> -1 
-1.51 -> -2 

EDIT2:

根据意见,我改变检查功能,这一个:

int round(double val) { 
    return (int)Math.Round(val, MidpointRounding.AwayFromZero); 
} 

更新的问题是:数学.Round功能是最快的舍入方式?

+0

你刚才不是执行'Math.Round'用'MidpointRounding.AwayFromZero'? –

+1

根据你的输出,这是'Math.Round'与'MidpointRounding.AwayFromZero' –

+0

当我深入研究它时,似乎我做了...... :-)但是,你能否提出做这样的最快方法四舍五入? – Jarda

回答

2

可以加快速度。这是更快的几倍:

 if (val >= 0) 
     { 
      return (int)(val + 0.5d); 
     } 
     return = (int)(val - 0.5d); 

您避免所有这些数学库的东西。问题是,它真的很重要吗?对于1500000次转换,您首次使用的时间为18ms。你的EDIT2功能是36ms。这个功能是4ms。

根据此测量,处理器可以比较两个双打,添加两个双打,并在大约2.5ns内转换一个。但是,如果它没有在缓存中,从主内存读取可能需要100ns。测量有时可能会产生误导。

下面是完整的代码

#region stopky 

     public class Stopky 
     { 
      [System.Runtime.InteropServices.DllImport("kernel32.dll")] 
      private static extern bool QueryPerformanceFrequency(out long frequency); 

      [System.Runtime.InteropServices.DllImport("kernel32.dll")] 
      private static extern bool QueryPerformanceCounter(out long ticks); 

      protected static double frequency = -1; 

      public void setStart() 
      { 
       QueryPerformanceCounter(out tickStart); 
      } 

      public double getTimeFromStart 
      { 
       get 
       { 
        QueryPerformanceCounter(out tickNow); 
        double time = (tickNow - tickStart)/frequency; 
        return time; 
       } 
      } 

      private long tickStart; 
      private long tickNow; 

      public Stopky() 
      { 
       if (frequency < 0) 
       { 
        long tmp; 
        QueryPerformanceFrequency(out tmp); 

        if (tmp == 0) 
        { 
         throw new NotSupportedException("Error while querying " 
       + "the high-resolution performance counter."); 
        } 

        frequency = tmp; 
       } 

       setStart(); 
      } 

      public void Show() 
      { 
       MessageBox.Show(this.getTimeFromStart.ToString()); 
      } 


     } 

     #endregion 




     private void button2_Click(object sender, EventArgs e) 
     { 
      double[] examples = new double[] { 0, 1, 1.1, 1.51, -0.1, -1, -1.1, -1.51 }; 

      int totalCount = 1500000; 

      double[] examplesExpanded = new double[totalCount]; 

      for (int i = 0, j = 0; i < examplesExpanded.Length; ++i) 
      { 
       examplesExpanded[i] = examples[j]; 

       if (++j >= examples.Length) { j = 0; } 
      } 

      int[] result1 = new int[totalCount]; 
      int[] result2 = new int[totalCount]; 
      int[] result3 = new int[totalCount]; 

      Stopky st = new Stopky(); 
      for (int i = 0; i < examplesExpanded.Length; ++i) 
      { 
       result1[i] = (int)Math.Round(examplesExpanded[i], MidpointRounding.AwayFromZero); 
      } 
      st.Show(); 
      st = new Stopky(); 
      for (int i = 0; i < examplesExpanded.Length; ++i) 
      { 
       double val = examplesExpanded[i]; 
       if (val >= 0) 
       { 
        result2[i] = (int)Math.Floor(val + 0.5); 
       } 
       result2[i] = (int)Math.Ceiling(val - 0.5); 
      } 
      st.Show(); 
      st = new Stopky(); 
      for (int i = 0; i < examplesExpanded.Length; ++i) 
      { 
       double val = examplesExpanded[i]; 
       if (val >= 0) 
       { 
        result3[i] = (int)(val + 0.5d); 
       } 
       else 
       { 
        result3[i] = (int)(val - 0.5d); 
       } 
      } 
      st.Show(); 

      for (int i = 0; i < totalCount; ++i) 
      { 
       if(result1[i] != result2[i] || result1[i] != result3[i]) 
       { 
        MessageBox.Show("ERROR"); 
       } 
      } 
      MessageBox.Show("OK"); 

     } 

的一些注意事项

  • 我< examplesExpanded.Length是略快于我< TOTALCOUNT,虽然它是直觉。原因是,范围检查可以避免。
  • 发行可显著快于调试(这里是差别不大)
+0

谢谢,这正是我正在寻找的答案...我已经做了一个基准测试,并且您的圆形函数版本比我的原始函数快10倍,比使用AwayFromZero舍入的函数快20倍 – Jarda

0

为什么不使用内置的Math.Round方法?

int round(double val) { 
    if (val >= 0) { 
     return Math.Round(val, MidpointRounding.AwayFromZero); 
    } 
    return Math.Round(val, MidpointRounding.ToEven); 
} 

https://msdn.microsoft.com/en-us/library/system.math.round(v=vs.110).aspx

+0

我不认为你的建议是正确的 - 例如,当我有val = -5时,那么你将返回-6,但我的将返回-5 ...并且存在正值的问题 – Jarda

+0

也许我误解了你正在做的事情。你是否可以用一些示例输入和输出来编辑你的问题,以及为什么你的方法写得像现在这样? – Steve

+0

查看我编辑的详细信息 – Jarda

相关问题