Algorithm 你能简化这个算法吗?

Algorithm 你能简化这个算法吗?,algorithm,refactoring,Algorithm,Refactoring,一个是给数学家的。这已经传遍了办公室,我们想看看谁能想出一个更好的优化版本 (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1)) ((a+p)1和&(b>=p))和 ((b-(a+p)=0)|(b-(a+p)>1)) 编辑:所有数据均为正整数 编辑:更好==为简单起见进行了重构我不

一个是给数学家的。这已经传遍了办公室,我们想看看谁能想出一个更好的优化版本

(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && 
    ((b - (a + p) == 0) || (b - (a + p) > 1))
((a+p)1和&(b>=p))和
((b-(a+p)=0)|(b-(a+p)>1))
编辑:所有数据均为正整数


编辑:更好==为简单起见进行了重构

我不会用那个表达式做所有的数学运算。例如,b-(a+p)被计算两次。如果可能,将它们拆分为变量


此外,编写一个波兰语注释树可能会帮助您优化它,您看到两次的所有内容都可以重复使用。

因为整数是无符号的,(a==0 | | a>1)可以替换为(a!=1)

第一次通过时,您可以将其简化为:

uint sum = a + p;
return ((sum <= b) && (a != 1) && (b >= p)) && (b - sum != 1);
uint sum=a+p;
返回((总和=p))&&(b-总和!=1);

此外,如果您能够为变量提供更有意义的名称,那么它的可读性会更好。例如,如果a和p是压力,那么a+p可以替换为PressureSum。

为了简单起见,通过引入更多表示每个表达式含义的局部变量进行重构。这对我们来说很难做到,因为我们不知道a、b和p是什么意思。

好吧

((b - (a + p) == 0) || (b - (a + p) > 1))

Would be better writen as:
(b - (a + p) >= 0)  

Applying this to the whole string you get:

((a+p) <= b) && (a > 1) && (b >= p)) && (b - (a + p) >= 0) 


(a + p) <= b is the same thing as b - (a + p) >= 0
((b-(a+p)==0)|(b-(a+p)>1))
最好写为:
(b-(a+p)>=0)
将其应用于您得到的整个字符串:
((a+p)1)和&(b>=p))和&(b-(a+p)>=0)
(a+p)=0
所以你可以摆脱这种离开:

((a+p) <= b) && (a > 1) && (b >= p)) 
((a+p)1)和&(b>=p))

第一次迭代:

bool bool1 = ((a+p) <= b) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (b - (a + p) == 0) || (b - (a + p) > 1);

return bool1 && bool2;
int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);

return bool1 && bool2;
int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (value2 >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);

return bool1 && bool2;
第三次迭代(所有正面)

第四次迭代(所有正面)

第五次迭代:

bool bool1 = ((a+p) <= b) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (b - (a + p) == 0) || (b - (a + p) > 1);

return bool1 && bool2;
int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);

return bool1 && bool2;
int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (value2 >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);

return bool1 && bool2;
编辑:好的,这不起作用,但这个:

a != 1 && b >= a+p && b-a-p != 1

因为它们都是正整数,所以可以消除很多重复:

所以作为第一步,

(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
((a+p)1和&(b>=p))和((b-(a+p)==0)| |(b-(a+p)>1))
变成

((a+p) <= b) && (a != 1) && (b >= p)) && ((b - (a + p) != 1) 
((a+p)=p))&((b-(a+p)!=1)
为清楚起见,这只是将
(foo==0 | | foo>1)
模式替换为
foo!=1


该模式在上面出现了两次,一次是foo=a,一次是foo=(b-(a+p))

如果公式有效并且来自您的业务规则,那么就不需要对其进行简化。编译器可能比我们更了解如何优化公式

您应该做的唯一一件事是使用更好的变量名称,以反映业务逻辑

在单元测试之前,请注意不要应用任何建议的解决方案

bap = b - (a + p)
bap >= 0 && bap != 1 && a != 1
编辑:现在我得到了-2,这是一个诚实的帮助尝试,也是一个我认为有效的答案。对于能够使用Python的人,这里有两个函数,一个带问题,一个带我的答案:

def question(a, b, p):
    return (((a+p) <= b) and (a == 0 or a > 1) and (b >= p)) or ((b - (a + p) == 0) or (b - (a + p) > 1))

def answer(a, b, p):
    bap = b - (a + p)
    return bap >= 0 and bap != 1 and a != 1
def问题(a、b、p):
返回(((a+p)1)和(b>=p))或((b-(a+p)==0)或(b-(a+p)>1))
def答案(a、b、p):
bap=b-(a+p)
返回bap>=0、bap!=1和a!=1
(a+p
选中,返回与问题相同的布尔值。

我用来检查的程序:(写得很开心)

#包括
使用名称空间std;
typedef无符号整数单元;
布尔条件(单元a、单元b、单元p)
{
uint s=a+p;
返回uint(b>=s&&a!=1&&b-s-1>0)
==uint(((a+p)1)和&(b>=p))
&&((b-(a+p)=0)|(b-(a+p)>1));
}
void main()
{
uint i=0;
uint j=0;
uint k=0;
最大常数=50;

对于(uint i=0;i好的,我希望我在这里做了我的数学,但是如果我是对的,那么这就简化了很多。尽管最后看起来不一样,但核心逻辑应该是一样的

// Initial equation
(((a + p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))

// ((a + p) <= b) iif a = 0 && p = b; therefore, b = p and a = 0 for this to work
(b == p) && ((b - (a + p) == 0) || (b - (a + p) > 1))

// Simplification, assuming that b = p and a = 0
(b == p) && (a == 0)
仅当a>=2时才计算为true;但是,如果以下条件也是true:

(b >= p)
这意味着p至少等于b,因此:

((a + p) <= b)
((a+p)

它可能不是最简单的,但应该是最可读的。

这是我能得到的最简单的

def calc(a, b, p):
    if (a != 1):
        temp = a - b + p
        if temp == 0 or temp < -1:
            return True
    return False
def计算(a、b、p):
如果(a!=1):
温度=a-b+p
如果温度==0或温度<-1:
返回真值
返回错误
也可以写为:

def calc(a, b, p):
    temp = a - b + p
    return a != 1 and (temp == 0 or temp < -1)
def计算(a、b、p):
温度=a-b+p
返回!=1和(温度==0或温度<-1)
或作为:

def calc(a, b, p):
    temp = a - b + p
    return a != 1 and temp <= 0 and temp != -1
def计算(a、b、p):
温度=a-b+p

返回a!=1和temp我将此作为对nickf答案的评论,但我认为我会自己给出答案。好的答案似乎都是他的变体,包括我的。但由于我们不依赖编译器进行优化(如果OP是,我们甚至不会这样做)然后将其从3个And分解为以下值,这意味着将有3个部分中只有2个需要计算的值。如果这是在脚本中完成的,那么与编译代码相比,它将产生不同

(a != 1) && ((b > (a + p + 1)) || (b == (a + p))))
根据评论,我将添加此wrt,它比和版本更好:


我想这取决于您的真实结果数据集是否大于输入集的50%。输入越是真实,我的变化就越好。因此,通过这个等式,它看起来和样式会更好(至少对于我的输入数据集0-500)。

使用从0到10000的a、b、p进行测试:

a != 1 && a != (b-p-1) && a <= (b-p);

a!=1&&a!=(b-p-1)和&a如果a、b和p是正整数(假设正范围包括0值),则表达式((a+p)1)和((b>=p))&((b-(a+p)==0)|(b-(a+p)>1))
可以减少到((a+p)=(a+p)),然后(b-(a+p))必须大于或等于0,我们需要确保(b-(a+p))!=1。
把这个词放在一边,继续说下去

现在我们可以集中精力在第一部分 ((a+p)1)和&(b>=p))&((b-(a+p))!=1)

如果a
(a!=1) && ((b==a+p) || (b>1+a+p))
def calc(a, b, p):
    if (a != 1):
        temp = a - b + p
        if temp == 0 or temp < -1:
            return True
    return False
def calc(a, b, p):
    temp = a - b + p
    return a != 1 and (temp == 0 or temp < -1)
def calc(a, b, p):
    temp = a - b + p
    return a != 1 and temp <= 0 and temp != -1
(a != 1) && ((b > (a + p + 1)) || (b == (a + p))))
a != 1 && a != (b-p-1) && a <= (b-p);
b >= (a+p) && a>=1
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
b>=(a+p)
**b>= (a+p)**
((a > 1) && (skeet == 0)) || ((a > 1) && (jon > 0) && (skeet < -1));
jon = (b - p)
skeet = (a - jon);
class Program
{
    static void Main(string[] args)
    {
        bool ok = true;
        for (int a = 1; a < 100; a++)
        {
            Console.Write(a.ToString());
            Console.Write("...");

            for (int b = 1; b < 100; b++)
            {
                for (int p = 1; p < 100; p++)
                {
                    bool[] results = testFunctions(a, b, p);
                    if (!allSame(results))
                    {
                        Console.WriteLine(string.Format(
                            "Fails for {0},{1},{2}", a, b, p));
                        for (int i = 1; i <= results.Length; i++)
                        {
                            Console.WriteLine(i.ToString() + ": " + 
                                results[i-1].ToString());
                        }

                        ok = false;
                        break;
                    }
                }
                if (!ok) { break; }
            }
            if (!ok) { break; }
        }
        if (ok) { Console.WriteLine("Success"); }
        else { Console.WriteLine("Failed!"); }
        Console.ReadKey();
    }

    public static bool allSame(bool[] vals)
    {
        bool firstValue = vals[0];
        for (int i = 1; i < vals.Length; i++)
        {
            if (vals[i] != firstValue)
            {
                return false;
            }
        }
        return true;
    }

    public static bool[] testFunctions(int a, int b, int p)
    {
        bool [] results = new bool[16];

        //given: all values are positive integers
        if (a<=0 || b<=0 || p<=0)
        {
            throw new Exception("All inputs must be positive integers!");
        }

        //[1] original expression
        results[0] = (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1));

        //[2] a==0 cannot be true since a is a positive integer
        results[1] = (((a+p) <= b) && (a > 1) && (b >= p)) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1));

        //[3] rewrite (b >= p) && ((a+p) <= b) 
        results[2] = (b >= p) && (b >= (a+p)) && (a > 1) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1));

        //[4] since a is positive, (b>=p) guarantees (b>=(p+a)) so we 
        //can drop the latter term
        results[3] = (b >= p) && (a > 1) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1));

        //[5] separate the two cases b>=p and b=p
        results[4] = ((b==p) && (a > 1) && ((b - (a + p) == 0) || 
            (b - (a + p) > 1))) || ((b > p) && (a > 1) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1)));

        //[6] rewrite the first case to eliminate p (since b=p 
        //in that case)
        results[5] = ((b==p) && (a > 1) && ((-a == 0) || 
            (-a > 1))) || ((b > p) && (a > 1) && 
            (((b - a - p) == 0) || ((b - a - p) > 1)));

        //[7] since a>0, neither (-a=0) nor (-a>1) can be true, 
        //so the case when b=p is always false
        results[6] = (b > p) && (a > 1) && (((b - a - p) == 0) || 
            ((b - a - p) > 1));

        //[8] rewrite (b>p) as ((b-p)>0) and reorder the subtractions
        results[7] = ((b - p) > 0) && (a > 1) && (((b - p - a) == 0) || 
            ((b - p - a) > 1));

        //[9] define (b - p) as N temporarily
        int N = (b - p);
        results[8] = (N > 0) && (a > 1) && (((N - a) == 0) || ((N - a) > 1));

        //[10] rewrite the disjunction to isolate a
        results[9] = (N > 0) && (a > 1) && ((a == N) || (a < (N - 1)));

        //[11] expand the disjunction
        results[10] = ((N > 0) && (a > 1) && (a == N)) ||
            ((N > 0) && (a > 1) && (a < (N - 1)));

        //[12] since (a = N) in the first subexpression we can simplify to
        results[11] = ((a == N) && (a > 1)) || 
            ((N > 0) && (a > 1) && (a < (N - 1)));

        //[13] extract common term (a > 1) and replace N with (b - p)
        results[12] = (a > 1) && ((a == (b - p)) || 
            (((b - p) > 0) && (a < (b - p - 1))));

        //[14] extract common term (a > 1) and replace N with (b - p)
        results[13] = (a > 1) && (((a - b + p) == 0) || 
            (((b - p) > 0) && ((a - b + p) < -1)));

        //[15] replace redundant subterms with intermediate 
        //variables (to make Jon Skeet happy)
        int jon = (b - p);
        int skeet = (a - jon);   //(a - b + p) = (a - (b - p))
        results[14] = (a > 1) && ((skeet == 0) || 
            ((jon > 0) && (skeet < -1)));

        //[16] rewrite in disjunctive normal form
        results[15] = ((a > 1) && (skeet == 0)) || 
            ((a > 1) && (jon > 0) && (skeet < -1));

        return results;
    }
}
((a == 0 || a > 1) && ((b-p) > 1) )
// In one line:
return (a != 1) && ((b-a-p == 0) || (b-a-p > 1))

// Expanded for the compiler:
if(a == 1)
    return false;

int bap = b - a - p;

return (bap == 0) || (bap > 1);
Require Import Arith.
Require Import Omega.

Lemma eq : forall (a b p:nat),
(((a+p) <= b) /\ ((a = 0) \/ (a > 1)) /\ (b >= p)) /\ 
    ((b - (a + p) = 0) \/ (b - (a + p) > 1)) <-> 
((a + p <= b) /\ ~ (a= 1) /\ ~ (b - a - p = 1)).
Proof. intros; omega. Qed.