Z3: семантика FMA с плавающей точкой
Z3 возвращает удовлетворительную модель для этого бенчмарка: http://rise4fun.com/Z3/Bnv5m
Однако запрос по существу утверждает, что a*b+0
эквивалентно a*b
с использованием инструкции FMA, которая, как я полагаю, выполняется для чисел с плавающей запятой IEEE. Обратите внимание, что бенчмарк явно гарантирует, что ни a
, ни b
не являются NaN
.
Есть ли проблема в моем кодировании FMA?
2 ответа:
Да, FMA в настоящее время глючит. Я сделал несколько исправлений для других инструкций в прошлую пятницу, но еще не удосужился исправить FMA. Спасибо за отчет и особенно за тестовый кейс, особенно в случае с FMA это неоценимая помощь!
Похоже, что их
(fusedMA <mode> foo bar baz)
возвращаетfoo*bar/2 + baz
. Что-то странное, либо в доказательстве теоремы, либо в реальном слитном умножении-сложении, кажется, происходит, когда либо аргументы, либо результат являются субнормальными.Я пробежал это, чтобы посмотреть, что он думает, что оскорбляющий продукт и FMA были:
(set-logic QF_FPA) ; s7 is equivalent to single-precision +0 (define-fun s7 () (_ FP 8 24) ((_ asFloat 8 24) roundNearestTiesToEven (/ 0 1))) (declare-fun s0 () (_ FP 8 24)) (declare-fun s1 () (_ FP 8 24)) (declare-fun prod () (_ FP 8 24)) (declare-fun fma () (_ FP 8 24)) (assert (let ((s2 (== s0 s0))) ; make sure s0 is not NaN (let ((s3 (== s1 s1))) ; make sure s1 is not NaN (let ((s4 (and s2 s3))) (let ((s5 (not s4))) ; s5 is True when either argument is NaN (let ((s6 (* roundNearestTiesToEven s0 s1))) ; s6 = s0*s1 (let ((s8 (fusedMA roundNearestTiesToEven s0 s1 s7))) ; s8 = s0*s1 + s7 = s0*s1 since s7 is 0 (let ((s9 (== s6 s8))) ; s9 should always be true provided arguments are not NaN (let ((s10 (or s5 s9))) ; thus; s10 is true always (and (== fma s8) (== prod s6) (not s10))))))))))) ; hence, the whole expression is unsatisfiable (check-sat) (get-model)
И получил вот что:
sat (model (define-fun prod () (_ FP 8 24) (as -1.0572719573974609375p-9 (_ FP 8 24))) (define-fun fma () (_ FP 8 24) (as -1.0572719573974609375p-10 (_ FP 8 24))) (define-fun s1 () (_ FP 8 24) (as +1.62525212764739990234375p118 (_ FP 8 24))) (define-fun s0 () (_ FP 8 24) (as -0.0101644992828369140625p-126 (_ FP 8 24))) )
Ни продукт, ни FMA на самом деле не соответствуют чему-то, что касается -2-14, то есть...утомительный.
Если вы связали
prod
иfma
ниже мимо 2-125, вы можете получить что-то вроде этого:sat (model (define-fun prod () (_ FP 8 24) (as +1.52807605266571044921875p-3 (_ FP 8 24))) (define-fun fma () (_ FP 8 24) (as +1.528076171875p-3 (_ FP 8 24))) (define-fun s1 () (_ FP 8 24) (as -0.0002593994140625p-126 (_ FP 8 24))) (define-fun s0 () (_ FP 8 24) (as -1.4381892681121826171875p125 (_ FP 8 24))) )
Если вы также связали
s0
иs1
ниже 2-125, он возвращаетunsat
.