首页 > 解决方案 > MiniZinc int 超出范围

问题描述

我正在尝试在 MiniZinc 中创建一个可以确定线和点之间距离的函数。我希望函数只使用整数。我的想法如下:在点不垂直线的情况下,应该选择最近的点。如果该点垂直于线,我想近似该点,然后计算到近似点的距离。

但是,当我实现这一点时,我不断收到类似以下 Gecode 和其他求解器的错误:

Error: The literal '-8004400200000' of the type int is out of range (-2147483646..2147483646) in line no. 13
Error: syntax error, unexpected FZ_DOTDOT in line no. 13
=====ERROR=====

为什么当它们远不接近最大整数值时,它会说 int 超出范围?

我的代码:

var 0..100: u;
var 0..100: v;
var 0..100: w;
var 0..100: x;
var 0..100: y;
var 0..100: z;

var 0..20000: a = distancePointLine(u, v, w, x, y, z);

function var 0..20000: distancePointLine(var 0..100: x, var 0..100: y, var 0..100: x1, var 0..100: y1, var 0..100: x2, var 0..100: y2) =
  let {
  var -200..200: dot = (x-x1) * (x2-x1) + (y-y1) * (y2-y1);
  var -2000..2000: dot10 = ((x-x1) * (x2-x1) + (y-y1) * (y2-y1)) * 10;
  var -20000..20000: len = (x2-x1) * (x2-x1) + (y2-y1) * (y2-y1);
  var 0..2000: param = if len == 0 then -1 else dot div len endif;
  var 0..10: onLine = if param != 0 then 1 else dot10 div len endif;
  var 0..100: xLine = if param < 0 then x1 elseif param >= 1 then x2 else pointLine(x1,x2,onLine) endif;
  var 0..100: yLine = if param < 0 then y1 elseif param >= 1 then y2 else pointLine(y1,y2,onLine) endif;
  var 0..20000: distance = (x-xLine) * (x - xLine) + (y-yLine) * (y-yLine);
  } in distance;
  
function var 0..100: pointLine(var int: x1, var int: x2, var 0..10: segment) = 
  let {
    var 0..100: point = 10 * x1 + segment * (x1-x2) div 10;
  } in point;
  
solve maximize a;

output [
         "Res: \(a) ",
         ];
    ```

标签: solverminizincgecode

解决方案


该错误表明某些计算值 (-8004400200000) 超出了可能支持的变量域(对于 Gecode,该域在 -2147483646..2147483646 范围内)。其原因distancePointLine是大多数变量被定义为,var int例如dot,,,,无限(和大)域。并且有一个非常大的域。dot10lendistance

要修复此特定问题的错误,您可以限制变量的域a,例如

var 0..10000: a = distancePointLine(7, 6, w, x, 100, 100);   

然后 Gecode 生成这个解决方案:

Res: 8649 
----------
==========

但是,即使这样,一些求解器(例如 Chuffed)仍然存在问题:它会抛出 Cannot handle non-sign-fixed vars.

如果可能的话,更好的方法是限制函数中变量的域distancePointLine


推荐阅读