Математически найти максимальное значение без условного сравнения

----------Обновлено ------------

codymanix и moonshadow были большой помощью до сих пор. Я смог решить свою проблему, используя уравнения, и вместо того, чтобы использовать правый сдвиг, я разделил на 29. Потому что с 32 битами подписано 2^31 = переполняется до 29. Что работает!

прототип в PHP

$r = $x - (($x - $y) & (($x - $y) / (29)));

фактический код для выводов (вы можете выполнять только одну математическую функцию в строке!!! ААА!!!)

DERIVDE1 = IMAGE1 - IMAGE2;
DERIVED2 = DERIVED1 / 29;
DERIVED3 = DERIVED1 AND DERIVED2;
MAX = IMAGE1 - DERIVED3;

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

я постараюсь сделать это просто. Мне нужно найти максимальные значения между двумя числами, не имея возможности использовать оператор IF или любой условный оператор.

чтобы найти максимальные значения, я могу выполнять только следующие функции

Divide, Multiply, Subtract, Add, NOT, AND ,OR

Допустим, у меня есть два числа

A = 60;
B = 50;

теперь, если A всегда больше B, это будет просто найти максимальное значение

MAX = (A - B) + B;
ex. 
10 = (60 - 50)
10 + 50 = 60 = MAX

проблема в том, что A не всегда больше B. Я не могу выполнять ABS, MAX, MIN или условные проверки с помощью скриптового приложения, которое я использую.

есть ли способ использовать ограниченную операцию выше, чтобы найти значение, очень близкое к максимальному?

14 ответов


поиск максимума из 2 переменных:

max = a-((a-b)&((a-b)>>31))

where > > - побитовое правое смещение (также называемое shr или ASR depeding on signedness).

вместо 31 вы используете количество битов ваши цифры минус один.


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

max = ((a+b)+|a-b|)/2;

здесь |a-b| является величиной разницы между a и b.


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


решения без условия. Приведите к uint, затем вернитесь к int, чтобы получить abs.

int abs (a) { return (int)((unsigned int)a); }
int max (a, b) { return (a + b + abs(a - b)) / 2; }

int max3 (a, b, c) { return (max(max(a,b),c); }

используя только логические операции, оценку короткого замыкания и предполагая соглашение c округления до нуля, можно выразить это как:

int lt0(int x) {
    return x && (!!((x-1)/x));
}

int mymax(int a, int b) {
    return lt0(a-b)*b+lt0(b-a)*a;
}

основная идея заключается в реализации оператора сравнения, который будет возвращать 0 или 1. Можно сделать аналогичный трюк, если ваш язык сценариев следует соглашению округления к значению пола, как это делает python.


Хммм. Я предполагаю, что нет, и, и или побитовые? Если это так, для решения этой проблемы будет побитовое выражение. Обратите внимание, что A | B даст число >= A и >= B. возможно, есть метод обрезки для выбора числа с наибольшим количеством битов.

чтобы расширить, нам нужно следующее, Чтобы определить, является ли a (0) или B (1) больше.

таблица истинности:

0|0 = 0  
0|1 = 1
1|0 = 0
1|1 = 0

!A and B

поэтому, даст индекс большего бита. Ergo, сравните каждый бит в обоих числах, и если они разные, используйте приведенное выше выражение (Не A и B), чтобы определить, какое число было больше. Начните с самого значительного бита и продолжите работу с обоих байтов. Если у вас нет конструкции цикла, вручную сравните каждый бит.

реализация ", когда они бывают разные":

(A != B) и (моя логика здесь)


попробуйте это, (но имейте в виду для переполнений) (Код в C#)

    public static Int32 Maximum(params Int32[] values)
    {
        Int32 retVal = Int32.MinValue;
        foreach (Int32 i in values)
            retVal += (((i - retVal) >> 31) & (i - retVal));
        return retVal;        
    }

function Min(x,y:integer):integer;
  Var
   d:integer;
   abs:integer;
 begin
  d:=x-y;
  abs:=d*(1-2*((3*d) div (3*d+1)));
  Result:=(x+y-abs) div 2;
 end;

вы можете выразить это как ряд арифметических и побитовых операций, например:

int myabs(const int& in) {
  const int tmp = in >> ((sizeof(int) * CHAR_BIT) - 1);
  return tmp - (in ^ tmp(;
}

int mymax(int a, int b) {
    return ((a+b) + myabs(b-a)) / 2;
}

пожалуйста, посмотрите на эту программу.. это может быть лучшим ответом до даты на этой странице...

#include <stdio.h>

int main()
{
    int a,b;
    a=3;
    b=5;
    printf("%d %d\n",a,b);
    b = (a+b)-(a=b); // this line is doing the reversal
    printf("%d %d\n",a,b);
    return 0;
}

//Assuming 32 bit integers 
int is_diff_positive(int num)
{
    ((num & 0x80000000) >> 31) ^ 1; // if diff positive ret 1 else 0
}
int sign(int x)
{
   return ((num & 0x80000000) >> 31);
}

int flip(int x)
{
   return x ^ 1;
}

int max(int a, int b)
{
  int diff = a - b;

  int is_pos_a = sign(a);
  int is_pos_b = sign(b);

  int is_diff_positive = diff_positive(diff);
  int is_diff_neg = flip(is_diff_positive);

  // diff (a - b) will overflow / underflow if signs are opposite
  // ex: a = INT_MAX , b = -3 then a - b => INT_MAX - (-3) => INT_MAX + 3
  int can_overflow = is_pos_a ^ is_pos_b;
  int cannot_overflow = flip(can_overflow);
  int res = (cannot_overflow * ( (a * is_diff_positive) + (b * 
            is_diff_negative)) + (can_overflow * ( (a * is_pos_a) + (b * 
            is_pos_b)));

  return res;

}

Это зависит от того, какой язык вы используете, но Тернарный Оператор может быть полезно.

но тогда, если вы не можете выполнять условные проверки в своем "скриптовом приложении", у вас, вероятно, нет троичного оператора.


если A всегда больше B .. [ можно использовать] .. MAX = (A - B) + B;

нет необходимости. Просто используйте:int maxA(int A, int B){ return A;}

(1) Если условия разрешают вам делать max = a>b ? a : b.

(2) Любой другой метод либо использует определенный набор чисел, либо полагается на неявные условные проверки.

(2а) max = a-((a-b)&((a-b)>>31)) это аккуратно, но это работает только if вы используете 32-битные числа. Вы можете развернуть его произвольным большим числом N, но метод потерпит неудачу, если вы пытаетесь найти max (N-1, N+1). Этот алгоритм работает для автоматов конечного состояния, но не для машины Тьюринга.

(2b) величина |a-b| условие |a-b| = a-b>0 a-b : b-a

о:
enter image description here

квадратный корень также является условием. Всякий раз, когда c>0 и c^2 = d у нас есть второе решение -c, потому что (-c)^2 = (-1)^2*c^2 = 1*c^2 = d. Квадратный корень возвращает наибольшее значение в паре. Я поставляется со сборкой в int max(int c1, int c2){return max(c1, c2);}

без сравнения операторная математика очень симметрична, а также ограничена по мощности. Положительные и отрицательные числа нельзя различить без if что-то в этом роде.


#region GetMaximumNumber
/// <summary>
/// Provides method to get maximum values.
/// </summary>
/// <param name="values">Integer array for getting maximum values.</param>
/// <returns>Maximum number from an array.</returns>
private int GetMaximumNumber(params int[] values)
{
  // Declare to store the maximum number.
  int maximumNumber = 0;
  try
  {
    // Check that array is not null and array has an elements.
    if (values != null &&
        values.Length > 0)
    {
      // Sort the array in ascending order for getting maximum value.
      Array.Sort(values);

      // Get the last value from an array which is always maximum.
      maximumNumber = values[values.Length - 1];
    }
  }
  catch (Exception ex)
  {
    throw ex;
  }
  return maximumNumber;
}
#endregion