【问题标题】:Mathematically Find Max Value without Conditional Comparison在没有条件比较的情况下在数学上找到最大值
【发布时间】:2010-11-25 10:36:46
【问题描述】:

---------更新了------------

到目前为止,codymanix 和 moonshadow 提供了很大的帮助。我能够使用方程式解决我的问题,而不是使用右移除以 29。因为 32 位有符号 2^31 = 溢出到 29。哪个有效!

PHP 中的原型

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

LEADS 的实际代码(每行只能执行一个数学函数!!!啊啊啊!!!)

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

---------原始问题------------
由于我的应用程序的限制,我认为这不太可能,但我认为值得一试。

我会尽量简化。我需要在无法使用 IF 或任何条件语句的情况下找到两个数字之间的最大值。

为了找到 MAX 值,我只能执行以下功能

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 或条件检查。

有没有办法使用上面的有限操作来找到一个非常接近最大值的值?

【问题讨论】:

  • 你可以使用按位运算吗?
  • "现在如果 A 总是大于 B,那么找到最大值会很简单" Ummm... A?
  • 为什么有人给出这个问题-1?这个问题没有错。但是你应该告诉你正在使用哪种编程语言。
  • 我可以执行的唯一操作是 (/, *, +, -, &, |, !) 我不能进行按位移位。我给出的例子是任意数字和变量。我不会知道信息的值,当然只是变量名。我正在使用一种未记录的自定义脚本语言,用于处理天气数据,在本例中为雷达。
  • 只是好奇:在这种情况下,您处于哪种类型的炼狱中?我们能把比尔盖茨关在那里吗?

标签: math conditional max algebra min


【解决方案1】:

如果我们设法找到两个数字之间的差异,我想这将是最简单的(只有大小没有符号)

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

其中|a-b|ab 之间的差异幅度。

【讨论】:

  • 这个答案非常有帮助。它还把我带到了min = ((a+b)-|a-b|)/2。非常感谢!
【解决方案2】:

finding the maximum of 2 variables:

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

其中 >> 是按位右移(也称为 SHR 或 ASR,取决于符号)。

您使用数字的位数减一,而不是 31。

【讨论】:

  • +1 请注意,这仅适用于 32 位。如果数字是 8/16/64 位 - 需要相应地更改“31”。
  • 如果不允许轮班: int max(int a, int b){ int c = a - b; int d = c & 0x7000;整数 e = d * -1;整数 f = e + 1;诠释 g = f & 0x1;返回 (g * a) | ((g*-1) * b); } 我使用了不同的变量,所以你可以看到每一步发生了什么。
  • 在 C 中,不需要符号扩展,IIRC,因此您的代码可能无法正常工作。此外,为了更便携,请将 31 替换为 sizeof(type)*8-1。
  • @codymanix:一种未记录的脚本语言,通过称为 LEADS 的天气应用程序使用。
  • 右移负数行为取决于实现,如图here
【解决方案3】:

如果您不能信任您的环境在可用时生成适当的无分支操作,请参阅this page 了解如何继续。注意输入范围的限制;如果您不能保证您的输入适合,请使用更大的整数类型。

【讨论】:

    【解决方案4】:

    没有条件的解决方案。转换为 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中,这个abs (a)a < 0时不返回绝对值。
    【解决方案5】:

    仅使用逻辑运算、短路评估并假设 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 那样遵循向底值取整的约定,则可以执行类似的技巧。

    【讨论】:

    • 我确实尝试过实现这个方法,但没有达到预期的效果。这确实帮助我弄清楚我的值没有被四舍五入,而是被转换为双精度值。啊!
    • 它将相对于零 (-c;c) 对的对称转换为相对于零对 (1;0) 对的不对称。这是通过嵌入舍入约定的隐式if 完成的。
    • a == b时不起作用
    【解决方案6】:
    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;
    

    【讨论】:

    • 这是什么语言?自然语言?漂亮你只使用初等运算符
    • 几年前我有一个计算器,它允许存储简单的公式,但没有条件或函数,如 abs 或 min/max。我希望我当时就知道这一点,有很多可能性。
    • @Et7f3XIV 这看起来像 Pascal 编程语言。
    【解决方案7】:

    嗯。我假设 NOT、AND 和 OR 是按位的?如果是这样,将有一个按位表达式来解决这个问题。注意 A | B 将给出一个数字 >= A 和 >= B。也许有一种修剪方法可以选择具有最多位数的数字。

    为了扩展,我们需要以下来确定A(0)或B(1)是否更大。

    真值表:

    0|0 = 0  
    0|1 = 1
    1|0 = 0
    1|1 = 0
    
    !A and B
    

    因此,将给出更大位的索引。因此,比较两个数字中的每个位,当它们不同时,使用上面的表达式(不是 A 和 B)来确定哪个数字更大。从最高有效位开始并向下处理两个字节。如果您没有循环结构,请手动比较每个位。

    实现“当它们不同时”:

    (A != B) AND(我的逻辑在这里)

    【讨论】:

    • 如果没有 shift(并且知道类型的大小(以字节为单位)),就无法做到这一点。
    • 是的,你可以。只需使用 2**bit_index 即可获得您的比较数字。
    • 记住“shift”只是乘以/除以2。
    • 如果为真,有没有办法在没有条件的情况下实现“当它们不同时”?
    • 但如果移位涉及符号位,我的建议中就是这种情况(>>31)
    【解决方案8】:

    试试这个,(但要注意溢出) (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;        
        }
    

    【讨论】:

      【解决方案9】:

      您可以将其表示为一系列算术和按位运算,例如:

      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;
      }
      

      【讨论】:

      • myabs(-6) 和 myabs(6) 给出 -6。所以它应该是 return (in ^ tmp) - tmp;
      【解决方案10】:
      //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;
      
      }
      

      【讨论】:

        【解决方案11】:

        这是我仅使用 +, -, *, %, / 运算符的实现

        using static System.Console;
        
        int Max(int a, int b) => (a + b + Abs(a - b)) / 2;
        int Abs(int x) => x * ((2 * x + 1) % 2);
        
        WriteLine(Max(-100, -2) == -2); // true
        WriteLine(Max(2, -100) == 2);   // true
        

        【讨论】:

          【解决方案12】:

          我只是想出了一个表达式: (( (a-b)-|a-b| ) / (2(a-b)) )*b + (( (b-a)-|b-a| )/(2(b-a)) )*a 如果 a>b 则等于 a,如果 b>a

          则等于 b

          当 a>b 时: a-b>0, a-b = |a-b|, (a-b)-|a-b| = 0 所以 b 的系数是 0

          b-a<0, b-a = -|b-a|, (b-a)-|b-a| = 2(b-a) 所以a的系数是2(b-a)/2(b-a),即1 所以如果 a 更大,它最终会返回 0*b+1*a,反之亦然

          【讨论】:

            【解决方案13】:

            在 n 和 m 之间找到 MAX

            MAX = ( (n/2) + (m/2) + ( ((n/2) - (m/2)) * ( (2*((n/2) - (m/2)) + 1) % 2) ) )
            
            在c中使用#define:
            #define MAX(n, m) ( (n/2) + (m/2) + ( ((n/2) - (m/2)) * ( (2*((n/2) - (m/2)) + 1) % 2) ) )
            
            #define ABS(n) ( n * ( (2*n + 1) % 2) )  // Calculates abs value of n
            #define MAX(n, m) ( (n/2) + (m/2) + ABS((n/2) - (m/2)) )  // Finds max between n & m
            #define MIN(n, m) ( (n/2) + (m/2) - ABS((n/2) - (m/2)) )  // Finds min between n & m
            

            【讨论】:

              【解决方案14】:

              请看看这个程序..这可能是迄今为止此页面上最好的答案...

              #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;
              }
              

              【讨论】:

                【解决方案15】:

                如果 A 总是大于 B .. [我们可以使用] .. MAX = (A - B) + B;

                不需要。只需使用:int maxA(int A, int B){ return A;}

                (1) 如果允许使用条件语句,您可以使用max = a&gt;b ? a : b

                (2) 任何其他方法要么使用一组定义的数字,要么依赖于隐式条件检查。

                (2a) max = a-((a-b)&amp;((a-b)&gt;&gt;31)) 这很简洁,但它只适用于 if 你使用 32 位数字。您可以将其扩展为任意大数 N,但如果您尝试找到 max(N-1, N+1),该方法将失败。该算法适用于有限状态自动机,但不适用于图灵机。

                (2b) 幅度|a-b| 是一个条件|a-b| = a-b&gt;0 a-b : b-a

                怎么样:

                平方根也是一个条件。每当c&gt;0c^2 = d 我们有第二个解决方案-c,因为(-c)^2 = (-1)^2*c^2 = 1*c^2 = d。平方根返回配对中的最大值。我有一个构建在int max(int c1, int c2){return max(c1, c2);}

                如果没有比较运算符,数学是非常对称的并且功率有限。如果没有某种if,就无法区分正数和负数。

                【讨论】:

                【解决方案16】:
                using System;
                namespace ConsoleApp2
                {
                    class Program
                    {
                        static void Main(string[] args)
                        {
                            float a = 101, b = 15;
                            float max = (a + b) / 2 + ((a > b) ? a - b : b - a) / 2;            
                        }
                    }
                }
                

                【讨论】:

                • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票
                • 问题要求没有条件比较的解决方案。这 ?运算符是条件比较。
                【解决方案17】:

                这取决于您使用的语言,但Ternary Operator 可能有用。

                但是,如果您无法在“脚本应用程序”中执行条件检查,您可能没有三元运算符。

                【讨论】:

                • 我确定他们不能使用 if,他们不能使用 ?: 要么
                • 该语言中没有可用的条件语句。
                • @Brian,这就是我所说的,但被否决了。也许答案中也不允许使用条件语句。
                【解决方案18】:
                #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
                

                【讨论】:

                • 完全不相关,并且对于数组中的最大数量效率低下。
                猜你喜欢
                • 2015-04-07
                • 1970-01-01
                • 2013-03-27
                • 1970-01-01
                • 2019-02-08
                • 1970-01-01
                • 1970-01-01
                • 2015-01-25
                • 2021-02-12
                相关资源
                最近更新 更多