Skip to content

Commit 66de726

Browse files
committed
FP theory: improve documentation and tests.
1 parent 3846f26 commit 66de726

File tree

2 files changed

+292
-5
lines changed

2 files changed

+292
-5
lines changed

src/org/sosy_lab/java_smt/api/FloatingPointFormulaManager.java

+89-5
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,16 @@ FloatingPointFormula castFrom(
298298

299299
FloatingPointFormula abs(FloatingPointFormula number);
300300

301+
/**
302+
* Returns the maximum value of the two given floating-point numbers. If one of the numbers is
303+
* NaN, the other number is returned.
304+
*/
301305
FloatingPointFormula max(FloatingPointFormula number1, FloatingPointFormula number2);
302306

307+
/**
308+
* Returns the minimum value of the two given floating-point numbers. If one of the numbers is
309+
* NaN, the other number is returned.
310+
*/
303311
FloatingPointFormula min(FloatingPointFormula number1, FloatingPointFormula number2);
304312

305313
FloatingPointFormula sqrt(FloatingPointFormula number);
@@ -345,36 +353,112 @@ FloatingPointFormula multiply(
345353

346354
/**
347355
* Create a term for assigning one floating-point term to another. This means both terms are
348-
* considered equal afterwards. This method is the same as the method <code>equal</code> for other
349-
* theories.
356+
* considered equal afterward, based on their bit pattern (i.e., <code>0.0 != -0
357+
* .0</code> and <code>NaN ==/!= NaN</code>, depending on the bit pattern of each NaN). This
358+
* method is the same as the method <code>equal</code> for other theories.
350359
*/
351360
BooleanFormula assignment(FloatingPointFormula number1, FloatingPointFormula number2);
352361

353362
/**
354363
* Create a term for comparing the equality of two floating-point terms, according to standard
355-
* floating-point semantics (i.e., NaN != NaN). Be careful to not use this method when you really
356-
* need {@link #assignment(FloatingPointFormula, FloatingPointFormula)}.
364+
* floating-point semantics (i.e., <code>NaN != NaN</code> and <code>0.0 == -0.0</code>). Be
365+
* careful to not use this method when you really need {@link #assignment(FloatingPointFormula,
366+
* FloatingPointFormula)}.
357367
*/
358368
BooleanFormula equalWithFPSemantics(FloatingPointFormula number1, FloatingPointFormula number2);
359369

370+
/**
371+
* Returns whether an FP number is greater than another FP number. If one of the numbers is NaN,
372+
* the result is always false.
373+
*/
360374
BooleanFormula greaterThan(FloatingPointFormula number1, FloatingPointFormula number2);
361375

376+
/**
377+
* Returns whether an FP number is greater or equal than another FP number. If one of the numbers
378+
* is NaN, the result is always false.
379+
*/
362380
BooleanFormula greaterOrEquals(FloatingPointFormula number1, FloatingPointFormula number2);
363381

382+
/**
383+
* Returns whether an FP number is less than another FP number. If one of the numbers is NaN, the
384+
* result is always false.
385+
*/
364386
BooleanFormula lessThan(FloatingPointFormula number1, FloatingPointFormula number2);
365387

388+
/**
389+
* Returns whether an FP number is less or equal than another FP number. If one of the numbers is
390+
* NaN, the result is always false.
391+
*/
366392
BooleanFormula lessOrEquals(FloatingPointFormula number1, FloatingPointFormula number2);
367393

394+
/**
395+
* Check whether a floating-point number is NaN.
396+
*
397+
* <p>The bit patterns for NaN in SMTLIB are identical to IEEE 754:
398+
*
399+
* <ul>
400+
* <li>sign=? (irrelevant for NaN)
401+
* <li>exponent=11...11 (all bits are 1)
402+
* <li>mantissa!=00...00 (mantissa is not all 0)
403+
*/
368404
BooleanFormula isNaN(FloatingPointFormula number);
369405

406+
/**
407+
* Checks whether a formula is positive or negative infinity.
408+
*
409+
* <p>The bit patterns for infinity in SMTLIB are identical to IEEE 754:
410+
*
411+
* <ul>
412+
* <li>sign=? (0 for +Inf, 1 for -Inf)
413+
* <li>exponent=11...11 (all bits are 1)
414+
* <li>mantissa=00...00 (all bits are 0)
415+
*/
370416
BooleanFormula isInfinity(FloatingPointFormula number);
371417

418+
/**
419+
* Checks whether a formula is positive or negative zero.
420+
*
421+
* <p>The bit patterns for zero in SMTLIB are identical to IEEE 754:
422+
*
423+
* <ul>
424+
* <li>sign=? (0 for +0, 1 for -0)
425+
* <li>exponent=00...00 (all bits are 0)
426+
* <li>mantissa=00...00 (all bits are 0)
427+
*/
372428
BooleanFormula isZero(FloatingPointFormula number);
373429

430+
/**
431+
* Checks whether a formula is normal FP number.
432+
*
433+
* <p>The bit patterns for normal FP numbers in SMTLIB are identical to IEEE 754:
434+
*
435+
* <ul>
436+
* <li>sign=? (0 for positive numbers, 1 for negative numbers)
437+
* <li>exponent!=00...00 and exponent!=11...11 (exponent is not all 0 or all 1)
438+
* <li>mantissa!=00...00 (mantissa is not all 0)
439+
*/
374440
BooleanFormula isNormal(FloatingPointFormula number);
375441

442+
/**
443+
* Checks whether a formula is subnormal FP number.
444+
*
445+
* <p>The bit patterns for subnormal FP numbers in SMTLIB are identical to IEEE 754:
446+
*
447+
* <ul>
448+
* <li>sign=? (0 for positive numbers, 1 for negative numbers)
449+
* <li>exponent=00...00 (exponent is all 0)
450+
* <li>mantissa!=00...00 (mantissa is not all 0)
451+
*/
376452
BooleanFormula isSubnormal(FloatingPointFormula number);
377453

378-
/** checks whether a formula is negative, including -0.0. */
454+
/**
455+
* Checks whether a formula is negative, including -0.0.
456+
*
457+
* <p>The bit patterns for negative FP numbers in SMTLIB are identical to IEEE 754:
458+
*
459+
* <ul>
460+
* <li>sign=1 (1 for negative numbers)
461+
* <li>number is not NaN, i.e., exponent=11...11 implies mantissa=00...00
462+
*/
379463
BooleanFormula isNegative(FloatingPointFormula number);
380464
}

src/org/sosy_lab/java_smt/test/FloatingPointFormulaManagerTest.java

+203
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,25 @@ public void nanAssignedNanIsTrue() throws SolverException, InterruptedException
190190
assertEqualsAsFormula(nan, nan);
191191
}
192192

193+
@Test
194+
public void nanOrdering() throws SolverException, InterruptedException {
195+
for (FloatingPointFormula other : new FloatingPointFormula[] {zero, posInf, negInf}) {
196+
assertThatFormula(fpmgr.greaterThan(nan, other)).isUnsatisfiable();
197+
assertThatFormula(fpmgr.greaterOrEquals(nan, other)).isUnsatisfiable();
198+
assertThatFormula(fpmgr.lessThan(nan, other)).isUnsatisfiable();
199+
assertThatFormula(fpmgr.lessOrEquals(nan, other)).isUnsatisfiable();
200+
assertEqualsAsFormula(fpmgr.max(nan, other), other);
201+
assertEqualsAsFormula(fpmgr.min(nan, other), other);
202+
203+
assertThatFormula(fpmgr.greaterThan(other, nan)).isUnsatisfiable();
204+
assertThatFormula(fpmgr.greaterOrEquals(other, nan)).isUnsatisfiable();
205+
assertThatFormula(fpmgr.lessThan(other, nan)).isUnsatisfiable();
206+
assertThatFormula(fpmgr.lessOrEquals(other, nan)).isUnsatisfiable();
207+
assertEqualsAsFormula(fpmgr.max(other, nan), other);
208+
assertEqualsAsFormula(fpmgr.min(other, nan), other);
209+
}
210+
}
211+
193212
@Test
194213
public void infinityOrdering() throws SolverException, InterruptedException {
195214
BooleanFormula order1 = fpmgr.greaterThan(posInf, zero);
@@ -320,6 +339,190 @@ public void specialValueFunctions() throws SolverException, InterruptedException
320339
assertThatFormula(fpmgr.isZero(minPosNormalValue)).isUnsatisfiable();
321340
}
322341

342+
@Test
343+
public void specialValueFunctionsFrom32Bits() throws SolverException, InterruptedException {
344+
float posInfFromBits = Float.intBitsToFloat(0x7f80_0000);
345+
assertThatFormula(fpmgr.isInfinity(fpmgr.makeNumber(posInfFromBits, singlePrecType)))
346+
.isTautological();
347+
348+
float negInfFromBits = Float.intBitsToFloat(0xff80_0000);
349+
assertThatFormula(fpmgr.isInfinity(fpmgr.makeNumber(negInfFromBits, singlePrecType)))
350+
.isTautological();
351+
352+
float zeroFromBits = Float.intBitsToFloat(0x0000_0000);
353+
assertThatFormula(fpmgr.isZero(fpmgr.makeNumber(zeroFromBits, singlePrecType)))
354+
.isTautological();
355+
356+
float negZeroFromBits = Float.intBitsToFloat(0x8000_0000);
357+
assertThatFormula(fpmgr.isZero(fpmgr.makeNumber(negZeroFromBits, singlePrecType)))
358+
.isTautological();
359+
360+
for (float nanFromBits :
361+
new float[] {
362+
Float.intBitsToFloat(0x7fc0_0001),
363+
Float.intBitsToFloat(0x7fc0_0002),
364+
Float.intBitsToFloat(0x7fc0_0003),
365+
Float.intBitsToFloat(0x7fc1_2345),
366+
Float.intBitsToFloat(0x7fdf_5678),
367+
Float.intBitsToFloat(0x7ff0_0001)
368+
// there are some more combinations for NaN, too much for one small test.
369+
}) {
370+
assertThatFormula(fpmgr.isNaN(fpmgr.makeNumber(nanFromBits, singlePrecType)))
371+
.isTautological();
372+
}
373+
}
374+
375+
@Test
376+
public void specialValueFunctionsFrom64Bits() throws SolverException, InterruptedException {
377+
double posInfFromBits = Double.longBitsToDouble(0x7ff0_0000_0000_0000L);
378+
assertThatFormula(fpmgr.isInfinity(fpmgr.makeNumber(posInfFromBits, doublePrecType)))
379+
.isTautological();
380+
381+
double negInfFromBits = Double.longBitsToDouble(0xfff0_0000_0000_0000L);
382+
assertThatFormula(fpmgr.isInfinity(fpmgr.makeNumber(negInfFromBits, doublePrecType)))
383+
.isTautological();
384+
385+
double zeroFromBits = Double.longBitsToDouble(0x0000_0000_0000_0000L);
386+
assertThatFormula(fpmgr.isZero(fpmgr.makeNumber(zeroFromBits, doublePrecType)))
387+
.isTautological();
388+
389+
double negZeroFromBits = Double.longBitsToDouble(0x8000_0000_0000_0000L);
390+
assertThatFormula(fpmgr.isZero(fpmgr.makeNumber(negZeroFromBits, doublePrecType)))
391+
.isTautological();
392+
393+
for (double nanFromBits :
394+
new double[] {
395+
Double.longBitsToDouble(0x7ff8_0000_0000_0001L),
396+
Double.longBitsToDouble(0x7ff8_0000_0000_0002L),
397+
Double.longBitsToDouble(0x7ff8_0000_0000_0003L),
398+
Double.longBitsToDouble(0x7ff8_1234_5678_9abcL),
399+
Double.longBitsToDouble(0x7ffc_9876_5432_1001L),
400+
Double.longBitsToDouble(0x7fff_ffff_ffff_fff2L),
401+
// there are some more combinations for NaN, too much for one small test.
402+
}) {
403+
assertThatFormula(fpmgr.isNaN(fpmgr.makeNumber(nanFromBits, doublePrecType)))
404+
.isTautological();
405+
}
406+
}
407+
408+
@Test
409+
public void specialValueFunctionsFrom32Bits2() throws SolverException, InterruptedException {
410+
requireBitvectors();
411+
FloatingPointFormula x = fpmgr.makeVariable("x32", singlePrecType);
412+
413+
assertThatFormula(fpmgr.isInfinity(x))
414+
.isEquivalentTo(
415+
bmgr.or(
416+
bvmgr.equal(fpmgr.toIeeeBitvector(x), bvmgr.makeBitvector(32, 0x7f80_0000L)),
417+
bvmgr.equal(fpmgr.toIeeeBitvector(x), bvmgr.makeBitvector(32, 0xff80_0000L))));
418+
419+
assertThatFormula(fpmgr.isZero(x))
420+
.isEquivalentTo(
421+
bmgr.or(
422+
bvmgr.equal(fpmgr.toIeeeBitvector(x), bvmgr.makeBitvector(32, 0x0000_0000)),
423+
bvmgr.equal(fpmgr.toIeeeBitvector(x), bvmgr.makeBitvector(32, 0x8000_0000L))));
424+
425+
assertThatFormula(fpmgr.isNormal(x))
426+
.isEquivalentTo(
427+
bmgr.and(
428+
bmgr.not(
429+
bvmgr.equal(
430+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 30, 23),
431+
bvmgr.makeBitvector(8, 0))),
432+
bmgr.not(
433+
bvmgr.equal(
434+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 30, 23),
435+
bvmgr.makeBitvector(8, -1)))));
436+
437+
assertThatFormula(fpmgr.isSubnormal(x))
438+
.isEquivalentTo(
439+
bmgr.and(
440+
bvmgr.equal(
441+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 30, 23), bvmgr.makeBitvector(8, 0)),
442+
bmgr.not(
443+
bvmgr.equal(
444+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 22, 0),
445+
bvmgr.makeBitvector(23, 0)))));
446+
447+
assertThatFormula(fpmgr.isNaN(x))
448+
.isEquivalentTo(
449+
bmgr.and(
450+
bvmgr.equal(
451+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 30, 23), bvmgr.makeBitvector(8, -1)),
452+
bmgr.not(
453+
bvmgr.equal(
454+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 22, 0),
455+
bvmgr.makeBitvector(23, 0)))));
456+
457+
assertThatFormula(fpmgr.isNegative(x))
458+
.isEquivalentTo(
459+
bmgr.and(
460+
bmgr.not(fpmgr.isNaN(x)),
461+
bvmgr.equal(
462+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 31, 31), bvmgr.makeBitvector(1, 1))));
463+
}
464+
465+
@Test
466+
public void specialValueFunctionsFrom64Bits2() throws SolverException, InterruptedException {
467+
requireBitvectors();
468+
FloatingPointFormula x = fpmgr.makeVariable("x64", doublePrecType);
469+
470+
assertThatFormula(fpmgr.isInfinity(x))
471+
.isEquivalentTo(
472+
bmgr.or(
473+
bvmgr.equal(
474+
fpmgr.toIeeeBitvector(x), bvmgr.makeBitvector(64, 0x7ff0_0000_0000_0000L)),
475+
bvmgr.equal(
476+
fpmgr.toIeeeBitvector(x), bvmgr.makeBitvector(64, 0xfff0_0000_0000_0000L))));
477+
478+
assertThatFormula(fpmgr.isZero(x))
479+
.isEquivalentTo(
480+
bmgr.or(
481+
bvmgr.equal(
482+
fpmgr.toIeeeBitvector(x), bvmgr.makeBitvector(64, 0x0000_0000_0000_0000L)),
483+
bvmgr.equal(
484+
fpmgr.toIeeeBitvector(x), bvmgr.makeBitvector(64, 0x8000_0000_0000_0000L))));
485+
486+
assertThatFormula(fpmgr.isNormal(x))
487+
.isEquivalentTo(
488+
bmgr.and(
489+
bmgr.not(
490+
bvmgr.equal(
491+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 62, 52),
492+
bvmgr.makeBitvector(11, 0))),
493+
bmgr.not(
494+
bvmgr.equal(
495+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 62, 52),
496+
bvmgr.makeBitvector(11, -1)))));
497+
498+
assertThatFormula(fpmgr.isSubnormal(x))
499+
.isEquivalentTo(
500+
bmgr.and(
501+
bvmgr.equal(
502+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 62, 52), bvmgr.makeBitvector(11, 0)),
503+
bmgr.not(
504+
bvmgr.equal(
505+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 51, 0),
506+
bvmgr.makeBitvector(52, 0)))));
507+
508+
assertThatFormula(fpmgr.isNaN(x))
509+
.isEquivalentTo(
510+
bmgr.and(
511+
bvmgr.equal(
512+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 62, 52), bvmgr.makeBitvector(11, -1)),
513+
bmgr.not(
514+
bvmgr.equal(
515+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 51, 0),
516+
bvmgr.makeBitvector(52, 0)))));
517+
518+
assertThatFormula(fpmgr.isNegative(x))
519+
.isEquivalentTo(
520+
bmgr.and(
521+
bmgr.not(fpmgr.isNaN(x)),
522+
bvmgr.equal(
523+
bvmgr.extract(fpmgr.toIeeeBitvector(x), 63, 63), bvmgr.makeBitvector(1, 1))));
524+
}
525+
323526
@Test
324527
public void specialDoubles() throws SolverException, InterruptedException {
325528
assertThatFormula(fpmgr.assignment(fpmgr.makeNumber(Double.NaN, singlePrecType), nan))

0 commit comments

Comments
 (0)