Сделать алгоритм C # более эффективным - PullRequest
2 голосов
/ 04 декабря 2008

У меня есть метод C #, который проецирует значение числа из интервала в целевой интервал.
Например: у нас есть интервал -1000 и 9000 и значение 5000; если мы хотим спроецировать это значение на интервал 0..100, мы получим 60.

Вот метод:

/// <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 ]

7 голосов
/ 04 декабря 2008

Только тысячи значений? Вам действительно нужно оптимизировать это дальше? Я не могу представить, что это на самом деле узкое место в данный момент. Вы профилировали приложение, чтобы убедиться, что это действительно проблема?

Учитывая, что метод O (1), вы не собираетесь проводить самый радикальный вид оптимизации, на который вы обычно нацелены, - улучшая сложность.

Сказав это - когда вы вызываете это тысячи раз, остается ли какое-либо из значений постоянным? Например, вы используете один и тот же минимум и максимум несколько раз? Если это так, вы можете создать класс, который принимает эти значения в конструкторах и предварительно вычисляет, что он может, а затем имеет метод, принимающий остальные параметры. Это немного улучшит ситуацию, но я вернусь к своей первоначальной точке - беспокойтесь об этом, только если это действительно вызывает проблемы.

4 голосов
/ 04 декабря 2008

Просто математика. То, что вы «проецируете», - это нормализация диапазонов A-B и A'-B ', такая что:

отношение r = (x-A) / (B-A) = (y-A ') / (B'-A')

который использует ваши условия:

(val-min) / (max-min) = (returnValue-intervalBottom) / (intervalTop-intervalBottom)

, который решает для returnValue как:

returnValue =  ((intervalTop-intervalBottom) * (val-min) / (max-min)) + intervalBottom
4 голосов
/ 04 декабря 2008

Ответы: НЕ используйте десятичную для быстрых операций.

Есть ли причина, по которой у вас не работает float или double?

2 голосов
/ 04 декабря 2008

В дополнение к тому, что вы не используете десятичную дробь, как уже было предложено, вы можете использовать ваши максимальные / минимальные значения где-то еще, чтобы вам не понадобились все эти вызовы Abs повсюду.

Я подозреваю, что только часть этого вам нужно сделать повторно - это умножение с плавающей запятой, сопровождаемое (или продолжающееся) добавлением с плавающей запятой. Все остальное можно предварительно проверить и рассчитать.

1 голос
/ 04 декабря 2008

Ваш код кажется более сложным, чем он должен быть на самом деле. Формула:

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

, что намного проще, чем ваша версия (и работает для целочисленных типов). Там нет условных веток (вызов Math.Min) или вызовов методов. ОК, это предполагает, что intervalTop

Если вы можете жить с типами данных int или float, одним из возможных решений является использование SIMD, но это будет означать написание кода на ассемблере, который может нарушить ваши требования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...