No hay caso en el que una división por cero pueda ocurrir aquí.
El SMT Solver Z3 admite aritmética precisa de coma flotante IEEE. Pidamos a Z3 que encuentre números a
y b
tal que a != b && (a - b) == 0
:
(set-info :status unknown)
(set-logic QF_FP)
(declare-fun b () (FloatingPoint 8 24))
(declare-fun a () (FloatingPoint 8 24))
(declare-fun rm () RoundingMode)
(assert
(and (not (fp.eq a b)) (fp.eq (fp.sub rm a b) +zero) true))
(check-sat)
El resultado es UNSAT
. No hay tales números.
La cadena SMTLIB anterior también permite a Z3 elegir un modo de redondeo arbitrario ( rm
). Esto significa que el resultado es válido para todos los modos de redondeo posibles (de los cuales hay cinco). El resultado también incluye la posibilidad de que cualquiera de las variables en juego sea NaN
infinita.
a == b
se implementa como fp.eq
calidad para que +0f
y se -0f
compare igual. La comparación con cero se implementa utilizando fp.eq
también. Dado que la pregunta tiene como objetivo evitar una división por cero, esta es la comparación adecuada.
Si la prueba de igualdad se implementó utilizando la igualdad de bits, +0f
y -0f
habría sido una forma de hacer a - b
cero. Una versión anterior incorrecta de esta respuesta contiene detalles de modo sobre ese caso para los curiosos.
Z3 Online aún no es compatible con la teoría FPA. Este resultado se obtuvo utilizando la última rama inestable. Se puede reproducir utilizando los enlaces .NET de la siguiente manera:
var fpSort = context.MkFPSort32();
var aExpr = (FPExpr)context.MkConst("a", fpSort);
var bExpr = (FPExpr)context.MkConst("b", fpSort);
var rmExpr = (FPRMExpr)context.MkConst("rm", context.MkFPRoundingModeSort());
var fpZero = context.MkFP(0f, fpSort);
var subExpr = context.MkFPSub(rmExpr, aExpr, bExpr);
var constraintExpr = context.MkAnd(
context.MkNot(context.MkFPEq(aExpr, bExpr)),
context.MkFPEq(subExpr, fpZero),
context.MkTrue()
);
var smtlibString = context.BenchmarkToSMTString(null, "QF_FP", null, null, new BoolExpr[0], constraintExpr);
var solver = context.MkSimpleSolver();
solver.Assert(constraintExpr);
var status = solver.Check();
Console.WriteLine(status);
Usando Z3 a responder a las preguntas IEEE flotador es agradable porque es difícil pasar por alto casos (como NaN
, -0f
, +-inf
) y se puede hacer preguntas arbitrarias. No es necesario interpretar y citar especificaciones. Incluso puede hacer preguntas mixtas flotantes y enteras como "¿es int log2(float)
correcto este algoritmo en particular ?".