diff --git a/src/Ibex.java.in b/src/Ibex.java.in index 6fafb02..9424f20 100644 --- a/src/Ibex.java.in +++ b/src/Ibex.java.in @@ -66,10 +66,26 @@ public class Ibex { * * prec[i]==-1 => the ith variable is integral. * prec[i]>=0 => the ith variable is real and the precision is prec[i]. - * + * + * @preserve_rounding - Under Linux/MacOS, Ibex (if linked with Gaol) does not use the standard + * rounding mode of the FPU (round-to-nearest) but the upward rounding mode, in order + * to get better performances. If preserve_rounding is true, Ibex will activate the + * upward rounding mode at each function call (contract, etc.) and restore the default + * rounding mode in return, which is transparent from Java but which also mean a loss + * of efficiency. If set to false, the rounding mode is only activated once by the + * construtor. In this case, the rounding mode is also changed on Java side. + */ + public Ibex(double[] prec, boolean preserve_rounding) { + init(prec, preserve_rounding); + } + + /** + * Same as previous constructor with preserve_rounding=false. + * + * For backward compatibility. */ public Ibex(double[] prec) { - init(prec); + init(prec, false); } /** @@ -272,7 +288,7 @@ public class Ibex { * * This method is automatically called by the constructor. */ - private native void init(double[] prec); + private native void init(double[] prec, boolean preserve_rounding); // Internal: do not modify! // This is a pointer to native c++ data diff --git a/src/ibex_Java.cpp.in b/src/ibex_Java.cpp.in index 01b532b..d2991e2 100644 --- a/src/ibex_Java.cpp.in +++ b/src/ibex_Java.cpp.in @@ -108,15 +108,19 @@ public: SmearSumRelative* bis; // bisector for the solver CellStack* stack; // cell buffer for the solver Solver* solver; // the solver - - Instance(int n, const BitSet& _params, const Vector& prec) : nb_var(n), params(_params), prec(prec), sys(NULL), - ctc(NULL), neg(NULL), bis(NULL), stack(NULL), solver(NULL) { + bool preserve_rounding; + + Instance(int n, const BitSet& _params, const Vector& prec, bool preserve_rounding) : nb_var(n), params(_params), prec(prec), sys(NULL), + ctc(NULL), neg(NULL), bis(NULL), stack(NULL), solver(NULL), preserve_rounding(preserve_rounding) { } void build() { //cout << " [ibex] new constraint:" << _syntax << " nb var=" << nb_var << " option=" << option << endl; + if (!preserve_rounding) + ibex_restore(); // do this once for all + stringstream s; for (size_t i=0; i0) s << ';'; @@ -201,8 +205,6 @@ Instance* get_instance(JNIEnv* env, jobject obj) { // either return BAD_POINT, UNKNOWN_POINT or INFLATE (the latter case also corresponds to the NOT_SIGNIFICANT case) jint inflate(NumConstraint& ctr, const IntervalVector& xin, IntervalVector& x, jboolean in) { - ibex_restore(); - jint result; Interval yin=ctr.f.eval(xin); @@ -235,7 +237,6 @@ jint inflate(NumConstraint& ctr, const IntervalVector& xin, IntervalVector& x, j } } - java_restore(); return result; } @@ -243,7 +244,7 @@ jint inflate(NumConstraint& ctr, const IntervalVector& xin, IntervalVector& x, j } -JNIEXPORT void JNICALL Java_@JAVA_SIGNATURE@_Ibex_init(JNIEnv* env, jobject obj, jdoubleArray _prec) { +JNIEXPORT void JNICALL Java_@JAVA_SIGNATURE@_Ibex_init(JNIEnv* env, jobject obj, jdoubleArray _prec, jboolean preserve_rounding) { jint size = env->GetArrayLength(_prec); jdouble* prec = env->GetDoubleArrayElements(_prec, 0); @@ -261,7 +262,7 @@ JNIEXPORT void JNICALL Java_@JAVA_SIGNATURE@_Ibex_init(JNIEnv* env, jobject obj, jclass clazz = env->GetObjectClass(obj); jfieldID _data = env->GetFieldID(clazz, "data", "J"); - env->SetLongField(obj ,_data, (jlong) new Instance(size, b, prec_vec)); + env->SetLongField(obj ,_data, (jlong) new Instance(size, b, prec_vec, preserve_rounding)); env->ReleaseDoubleArrayElements(_prec, prec, 0); } @@ -285,19 +286,19 @@ JNIEXPORT jboolean JNICALL Java_@JAVA_SIGNATURE@_Ibex_build(JNIEnv* env, jobject Instance& inst = *get_instance(env,obj); - ibex_restore(); // required as the parser may perform interval ops + if (inst.preserve_rounding) ibex_restore(); // required as the parser may perform interval ops if (inst.sys==NULL) { try { inst.build(); - java_restore(); + if (inst.preserve_rounding) java_restore(); return true; } catch(SyntaxError&) { - java_restore(); + if (inst.preserve_rounding) java_restore(); return false; } } else { - java_restore(); + if (inst.preserve_rounding) java_restore(); return true; } } @@ -311,7 +312,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_contract__I_3DID(JNIEnv* env, return NOT_BUILT; } - ibex_restore(); + if (inst.preserve_rounding) ibex_restore(); jint result = NOTHING; // by default @@ -319,7 +320,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_contract__I_3DID(JNIEnv* env, IntervalVector box=inst.read_box(env,d,env->GetArrayLength(_d)); if (box.is_empty()) { env->ReleaseDoubleArrayElements(_d, d, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return BAD_DOMAIN; } @@ -384,7 +385,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_contract__I_3DID(JNIEnv* env, env->ReleaseDoubleArrayElements(_d, d, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return result; } @@ -408,7 +409,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_inflate(JNIEnv* env, jobject o return NOT_BUILT; } - ibex_restore(); + if (inst.preserve_rounding) ibex_restore(); jint result; @@ -416,7 +417,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_inflate(JNIEnv* env, jobject o IntervalVector x=inst.read_box(env,d,env->GetArrayLength(_d)); if (x.is_empty()) { env->ReleaseDoubleArrayElements(_d, d, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return BAD_DOMAIN; } @@ -424,7 +425,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_inflate(JNIEnv* env, jobject o if (env->GetArrayLength(_din)!=inst.nb_var) { env->ReleaseDoubleArrayElements(_d, d, 0); env->ReleaseDoubleArrayElements(_din, din, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return BAD_DOMAIN; } @@ -491,7 +492,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_inflate(JNIEnv* env, jobject o env->ReleaseDoubleArrayElements(_d, d, 0); env->ReleaseDoubleArrayElements(_din, din, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return result; } @@ -503,20 +504,20 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_start_1solve(JNIEnv* env, jobj return NOT_BUILT; } - ibex_restore(); + if (inst.preserve_rounding) ibex_restore(); jdouble* d = env->GetDoubleArrayElements(_d, 0); IntervalVector box=inst.read_box(env,d,env->GetArrayLength(_d)); if (box.is_empty()) { env->ReleaseDoubleArrayElements(_d, d, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return BAD_DOMAIN; } for (int i=0; iReleaseDoubleArrayElements(_d, d, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return STARTED; } @@ -536,7 +537,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_next_1solution(JNIEnv* env, jo return NOT_BUILT; } - ibex_restore(); + if (inst.preserve_rounding) ibex_restore(); jint result; @@ -545,7 +546,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_next_1solution(JNIEnv* env, jo IntervalVector box=inst.read_box(env,d,env->GetArrayLength(_d)); if (box.is_empty()) { env->ReleaseDoubleArrayElements(_d, d, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return BAD_DOMAIN; } @@ -564,7 +565,7 @@ JNIEXPORT jint JNICALL Java_@JAVA_SIGNATURE@_Ibex_next_1solution(JNIEnv* env, jo env->ReleaseDoubleArrayElements(_d, d, 0); - java_restore(); + if (inst.preserve_rounding) java_restore(); return result; } diff --git a/tests/IbexTest.java.in b/tests/IbexTest.java.in index 6e7d118..821a51d 100644 --- a/tests/IbexTest.java.in +++ b/tests/IbexTest.java.in @@ -260,6 +260,26 @@ public class IbexTest { } + @Test + public void test_correct_rounding1() { + Ibex ibex = new Ibex(new double[]{1.e-1, 1.e-1, 1.e-4}, false); + ibex.add_ctr("{0}+{1}={2}"); + ibex.build(); + double domains[] = {0.1, 0.1, 0.2, 0.2, -5.0, 5.0}; + int result = ibex.contract(0, domains); + Assert.assertEquals(Ibex.CONTRACT, result); + } + + @Test + public void test_correct_rounding2() { + Ibex ibex = new Ibex(new double[]{1.e-1, 1.e-1, 1.e-4}, true); + ibex.add_ctr("{0}+{1}={2}"); + ibex.build(); + double domains[] = {0.1, 0.1, 0.2, 0.2, -5.0, 5.0}; + int result = ibex.contract(0, domains); + Assert.assertEquals(Ibex.CONTRACT, result); + } + public static void main(String args[]) { org.junit.runner.JUnitCore.main("IbexTest"); }