代码之家  ›  专栏  ›  技术社区  ›  Germstorm Pierre-Alain Vigeant

使C#算法更有效

  •  2
  • Germstorm Pierre-Alain Vigeant  · 技术社区  · 17 年前

    我有一个C#方法,它将一个数字的值从一个区间投影到一个目标区间。
    例如:

    /// <summary>  
    /// Projects a value to an interval
    /// </summary>
    /// <param name="val">The value that needs to be projected</param>  
    /// <param name="min">The minimum of the interval the value comes from</param>  
    /// <param name="max">The maximum of the interval the value comes from</param>  
    /// <param name="intervalTop">The minimum of the interval the value will 
    /// be projected to</param>  
    /// <param name="intervalBottom">The maximum of the interval the value will 
    /// be projected to</param>  
    /// <returns>Projected value</returns> 
    public decimal ProjectValueToInterval(decimal val,  
                                          decimal min,  
                                          decimal max,  
                                          decimal intervalBottom, 
                                          decimal intervalTop)  
    {  
        decimal newMin = Math.Min(0, min);
        decimal valueIntervalSize = Math.Abs(max - newMin);
        decimal targetIntervalSize = Math.Abs(intervalTop - intervalBottom);
    
        decimal projectionUnit = targetIntervalSize / valueIntervalSize;
    
        return (val * projectionUnit) + Math.Abs((newMin * projectionUnit));
    }
    

    需要为数千个值调用此方法。
    我想知道在C#中是否有更有效的方法来实现这一点?如果是,您建议进行哪些更改?

    5 回复  |  直到 17 年前
        1
  •  7
  •   Jon Skeet    17 年前

    只有数千个值?你真的需要进一步优化吗?我无法想象目前它实际上是一个瓶颈。您是否分析了应用程序以检查这是否真的是一个问题?

    考虑到方法是O(1),你不会做出你通常所追求的最激烈的优化——提高复杂性。

    话虽如此,当你调用它数千次时,有任何值保持不变吗?例如,是否重复使用相同的最小值和最大值?如果是这样,您可以创建一个类,该类接受构造函数中的这些值并预计算它所能做的,然后有一个方法接受其余的参数。这将略微改善情况,但我回到了我最初的观点——如果这真的导致了问题,我只担心这一点。

        2
  •  4
  •   leppie    17 年前

    有没有什么理由让float或double不适合你?

        3
  •  4
  •   annakata    17 年前

    比率r=(x-A)/(B-A)=(y-A')/(B'-A'))

    使用您的术语是:

    它将returnValue解为:

    returnValue =  ((intervalTop-intervalBottom) * (val-min) / (max-min)) + intervalBottom
    
        4
  •  2
  •   Will Dean    17 年前

    除了不使用已经建议过的十进制外,您还可以在其他地方对最大/最小值进行santise,这样您就不需要到处调用Abs。

    我想这只是你需要做的一部分 反复地 浮点乘法后接(或进行)浮点加法。其他一切都可以预先检查&预先计算的。

        5
  •  1
  •   Tim Cooper    14 年前

    intervalTop + (intervalBottom - intervalTop) * (val - min) / (max - min);
    

    这比您的版本简单得多(适用于整型)。其中没有条件分支(Math.Min调用)或方法调用。好的,它假设intervalTop<间隔底部和最小值<max.如果intervalTop、intervalBottom、min和max对于一组值是常量,那么您可以预计算(intervalBottom-intervalTop)和(max-min),并将这些结果用于对函数的所有调用。可以消除的另一个开销是将函数内联到调用循环中。我不知道C#(或者更确切地说是JIT编译器)对内联方法做了什么,所以这可能已经在幕后发生了。

    如果您可以使用int或float数据类型,一种可能的解决方案是使用SIMD,但这将意味着编写本机汇编代码,这可能会破坏您的需求。