Установить объемный размер, используя арифметическое выражение вместо троичного выражения - PullRequest
0 голосов
/ 04 июня 2018

В следующем фрагменте (жестко закодированные значения являются только примером):

int nBulk = 30,      // bulk size
    nMax = 130;      // max records to retrieve
    nRetrieved = 0;  // records retrieved so far
do
{
   var response = GetRecords(nBulk);
   nRetrieved += response.Count;
   nBulk = nMax - nRetrieved >= nBulk ? nBulk : nMax - nRetrieved;
}
while (nRetrieved < response.Total && nRetrieved < nMax);

nBulk присваивается новое значение с использованием троичного выражения.

Можно ли заменить троичное выражение простым арифметическим выражением (т.е. без ветвей)?

Ответы [ 2 ]

0 голосов
/ 14 июня 2018

Ответ Да , но это довольно уродливо:

nBulk = (nBulk + (nMax - nRetrieved) + Math.Abs(nBulk - (nMax - nRetrieved)))/2;

Если вы хотите избежать Abs, вы можете сделать это следующим образом:

nBulk = (nBulk + (nMax - nRetrieved) 
      + Math.Sqrt((nBulk - (nMax - nRetrieved)) * (nBulk - (nMax - nRetrieved))))/2;

, что, вероятно, еще хуже.

Короче говоря, не существует хорошего способа "языковой агностики", потому что не существует метода Lanugae Agnostic для преобразования логических значений в целые числа без разветвления.На тех языках, где вы не можете просто сказать:

int i = (true);

, тогда это другая история.

0 голосов
/ 04 июня 2018

Ничто не указывает на то, что nMax==response.Total: следовательно, я делаю вывод, что последний GetRecords запрос будет эффективно возвращать nRetrieved <= nRequested.

Если GetRecords имеет эту способность для чтения достаточно доступным, естьнет необходимости изменять nBulk внутри цикла из кода, который вы показываете.

Однако, если бы я увидел такой код, я бы сделал вывод, что изменение nBulk для последнего чтения может быть необходимо, потому что *У 1011 * есть побочный эффект - как заполнение буфера - IOW, что защита абсолютно необходима, чтобы избежать переполнения буфера.

В этом случае ветвление будет наименьшей из проблем: наличиеизменяющие метод / функцию состояния, но требующие знания ограничения внутреннего буфера (nMax) на сайте отправителя / вызывающего абонента, опасны!

Вот почему я склонен перемещать защиту по отношению к.nMax внутри метода / функции GetRecords, а не снаружи, и если вы это сделаете, проблема будет решена на сайте отправки: больше не нужно изменять nBulk в цикле и не нужно придумывать о nMax.

Конечно, тест будет перемещен внутрь GetRecords и, следовательно, не исчезнет.Но, честно говоря, почему это будет проблемой?Не могли бы вы увеличить объем, чтобы этот тест стал абсолютно пренебрежимым?

Если вы не можете по какой-либо причине, то:

  1. Выполните первое чтение, чтобы получить общий оставшийся размер дочитать
  2. обрабатывать случай, когда nRemaining> = nMax, обрезая до nMax вне цикла
  3. loop, пока nRemaining> = nBulk, и уменьшать nRemaining путем эффективного nRetrieved
  4. выполнить последнееGetRecords с запросом nRemaining.

В цикле все еще есть тест (nRemaining> = nBulk), поэтому все это кажется довольно бесполезным.

Чтобы избежать этого теста, вы должны бытьубедитесь, что фактически nRetrieved равно запрошенному nBulk, когда достаточно получить (ничего не указывает на это в вашем коде).

В этом случае вы можете выполнить деление на шаге 3.nLoop=integer_floor_division(Total/nBulk), выполните это количество циклов (и попросите некоторый компилятор развернуть цикл для вас, чтобы уменьшить количество тестов в среднем), затем выполните GetRecords для remaining (modulo / remainder) Total%nBulk на шаге 4.

Все, что вы получите, - это код IMO, более хрупкий и хрупкий, с риском уничтожения предельных выгод за счет заполнения кэша кода ... ВопросВы должны спросить: действительно ли мне нужна эта микрооптимизация и почему?

...