查找满足特定条件的最接近整数值的算法

Algorithm to find closest integer values that meet certain criteria

编辑以通过添加单位 (ml) 和解释以 1/26 为单位测量湿试剂的难度来澄清应用程序。 'solution'这个词是有歧义的,因为它被用来表示化学溶液和问题的解决方案。

根据爱德华的回复添加了结果

现实世界的应用是,我试图确定最接近的 "convenient" 体积,以便在混合试剂 A 和 B 以创建最接近特定 [= 的溶液(在湿化学意义上)时使用45=]比例。让我们定义 "convenient" 可以被 5 整除。

示例

给定:

1. X = A/(A+B) * C 
2. Y = B/(A+B) * C
3. X + Y = C
4. A, B, C always positive integer

// e.g. a 500ml solution (wet chemistry sense) C with a 1:25 ratio of A and B 
A = 1
B = 25
C = 500

这给出了使用 XY 的体积来创建具有适当 A:B 比例的溶液(湿化学意义)。

X =   500/26 = ~19.23ml
Y = 12500/26 = ~480.77ml
C = 13000/26 = 500ml

这些是创建 500 毫升总体积的确切体积,但尝试以 1/26 毫升为单位测量试剂体积是一个挑战。

如何找到 X、Y 和 C 的 "convenient values"(可被 5 整除的整数)最接近 1/26 的倍数的 X、Y 和 C 的精确值?在这种情况下,我发现 X、Y、C 的最接近 "convenient" 值:

X =  20ml
Y = 500ml
C = 520ml

C 在这种情况下 (520ml) 大于所需的 500ml 体积,但物理测量 20mL 和 500mL 的体积比测量 1/26 的试剂体积更实用。多余的 20mL 被丢弃,这是使用 nice 值的代价。

结果基于爱德华的回答

A=1   B=25    C=500
X=20  Y=500  C2=520 

A=1   B=20    C=500
X=25  Y=500  C2=525 

A=1   B=100   C=500
X=5   Y=500  C2=505 

A=1   B=75    C=500
X=10  Y=750  C2=760 

A=1   B=50    C=900
X=20  Y=1000 C2=1020 

让我们首先计算最优(浮动)A 和 B。

可以观察到最佳整数解是 {floor(A), ceiling(B)} 或 {ceiling(A), floor(B)}。所以我们简单地尝试两者并选择错误较少的答案。

解决此问题的一种方法是调整 C,使其吸收因子 A+B。那么 AB 的比率就是精确的,并且 XYC 都是整数。让 D = 5*(A+B)C2 = ceiling(C/((double)D)) * D(四舍五入以便得到足够的 C)、X = C2/(A+B)*AY = C2/(A+B)*B。如果您想要 C 的最接近值,请改用 C2 = round(C/((double)D))*D

如果您要混合化学品,您可能希望四舍五入而不是四舍五入到最接近的位置,这样您就足够了,剩下一点废物,这总比不够好。

您可以将其表述为具有 L1(绝对值)objective 函数的优化问题。 (这是用大炮打蚊子,但我这样做是因为我想弄清楚 L1 优化。)我使用了 GLPK 包(开源)中的程序 glpsol。这是我的程序:

param A, integer, >= 0;
param B, integer, >= 0;
param C, integer, >= 0;
var x, integer, >= 0;
var y, integer, >= 0;
var e1x, >= 0;
var e1y, >= 0;

minimize e1 : e1x + e1y;

subject to

  c1 : (5*x - (C*A)/(A + B)) <= e1x;
  c2 : ((C*A)/(A + B) - 5*x) <= e1x;
  c3 : (5*y - (C*B)/(A + B)) <= e1y;
  c4 : ((C*B)/(A + B) - 5*y) <= e1y;

solve;

printf "x=%g, y=%g, error=%g\n", x, y, e1;

data;

param A := 1;
param B := 25;
param C := 500;

这是输出:

$ glpsol --model find_nice_integers.mod 
[... snip ...]
x=4, y=96, error=1.53846

这里有一些关于 how to handle absolute values in optimization problems 的注释。

因此,给你一个整数 C 以及另外两个整数 AB 之间的比率 p:q(即 A/B = p/q ).

我会将您对 convenient 的定义解释为要求 XY 都是 5 的倍数,其中

X = A / (A+B) * C'
Y = B / (A+B) * C'
C' is close to C

p/q 替换 A/B 我们得到

X = p / (p+q) * C'
Y = q / (p+q) * C'

现在,为了使 XY 成为整数,p * C'q * C' 都必须是 (p+q) 的倍数。并且由于我们可以假设 p:q 是不可约的(即 pq 没有共同的倍数)这意味着 C' 必须被 p+q 整除.此外,C'/(p+q) 必须是 5 的倍数。所以,C' 必须是 5*(p+q).

的倍数

最接近C5*(p+q)的倍数是:

C' := round(C/(5*(p+q)))*5*(p+q)

现在我们可以计算:

X := p/(p+q)*C'
Y := q/(p+q)*C'

它们确实是 5 的倍数,因为 C'/(p+q) 是。

让我们看看你的例子是如何表现的:

输入:

p = 1
q = 25
C = 500

然后

C' := round(500/5(1+25))*5*(1+25) = round(100/26)*5*26 = 4*5*26 = 520

因此

X := p/(p+q)*C' = 1/(1+25)*4*5*26 = 1/26*4*5*26 = 4*5 = 20
Y := q/(p+q)*C' = 25/(1+25)*4*5*26 = 25/26*4*5*26 = 25*4*5 = 500.

瞧!