Здесь не может быть деления на ноль.
SMT Solver Z3 поддерживает точную IEEE арифметику с плавающей точкой. Давайте попросим Z3 найти числа a
и b
такие, что 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)
Результат UNSAT
. Таких номеров нет.
Вышеупомянутая строка SMTLIB также позволяет Z3 выбрать произвольный режим округления ( rm
). Это означает, что результат верен для всех возможных режимов округления (их пять). Результат также включает возможность того, что любая из переменных в игре может иметь значение NaN
или бесконечность.
a == b
реализовано как fp.eq
качество, так что +0f
и -0f
сравнивать равно. Сравнение с нулем осуществляется с помощьюfp.eq
. Поскольку вопрос направлен на то, чтобы избежать деления на ноль, это подходящее сравнение.
Если бы проверка на равенство была реализована с использованием побитового равенства, +0f
и -0f
это был бы способ сделать a - b
ноль. Некорректная предыдущая версия этого ответа содержит подробные сведения о режиме для любопытных.
Z3 Online пока не поддерживает теорию FPA. Этот результат был получен с использованием последней нестабильной ветки. Его можно воспроизвести с помощью привязок .NET следующим образом:
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);
Использование Z3 , чтобы ответить на вопросы IEEE с плавающей точкой приятно , потому что это трудно игнорировать случаи (например NaN
, -0f
, +-inf
) , и вы можете задать произвольные вопросы. Нет необходимости интерпретировать и цитировать спецификации. Вы даже можете задавать смешанные вопросы с числами с плавающей запятой и целыми числами, такие как « int log2(float)
правильный ли этот алгоритм?».