123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570(*
Copyright 2011 Jean-Marc Alliot / Jean-Baptiste Gotteland
Copyright 2018 Christophe Troestler
This file is part of the ocaml interval library.
The ocaml interval library is free software:
you can redistribute it and/or modify it under the terms of
the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The ocaml interval library is distributed in the hope that it will be
useful,but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the ocaml interval library.
If not, see <http://www.gnu.org/licenses/>.
*)moduletypeT=sigtypenumbertypetvalzero:tvalone:tvalpi:tvaltwo_pi:tvalhalf_pi:tvale:tvalentire:tvalv:number->number->tvallow:t->numbervalhigh:t->numbervalof_int:int->tvalto_string:?fmt:(number->'b,'a,'b)format->t->stringvalpr:out_channel->t->unitvalpp:Format.formatter->t->unitvalfmt:(number->'b,'a,'b)format->(t->'c,'d,'e,'c)format4valcompare_f:t->number->intvalis_bounded:t->boolvalis_entire:t->boolvalequal:t->t->boolval(=):t->t->boolvalsubset:t->t->boolval(<=):t->t->boolval(>=):t->t->boolvalprecedes:t->t->boolvalinterior:t->t->boolval(<):t->t->boolval(>):t->t->boolvalstrict_precedes:t->t->boolvaldisjoint:t->t->boolvalwidth:t->tvalwidth_high:t->numbervalwidth_low:t->numbervalmag:t->numbervalmig:t->numbervalsgn:t->tvaltruncate:t->tvalabs:t->tvalhull:t->t->tvalinter_exn:t->t->tvalinter:t->t->toptionvalmax:t->t->tvalmin:t->t->tval(+):t->t->tval(+.):t->number->tval(+:):number->t->tval(-):t->t->tval(-.):t->number->tval(-:):number->t->tval(~-):t->tval(*):t->t->tval(*.):number->t->tval(*:):t->number->tval(/):t->t->tval(/.):t->number->tval(/:):number->t->tvalinv:t->ttype'aone_or_two=Oneof'a|Twoof'a*'avalinvx:t->tone_or_twovalcancelminus:t->t->tvalcancelplus:t->t->tval(**):t->int->tend(* [min] and [max], specialized to floats (faster).
NaN do dot need to be handled (see [I.v]). *)let[@inline]fmin(a:float)(b:float)=ifa<=bthenaelseblet[@inlne]fmax(a:float)(b:float)=ifa<=bthenbelsealet[@inline]is_evenx=xland1=0(* Base [Low] module. *)moduleL=structmoduleU=Interval__Utypet=floatletzero=0.letone=1.letpi=0x1.921fb54442d18p1lettwo_pi=0x1.921fb54442d18p2lethalf_pi=0x1.921fb54442d18p0lete=0x1.5bf0a8b145769p1externalfloat:(int[@untagged])->(float[@unboxed])="ocaml_low_float_byte""ocaml_low_float"external(+.):float->float->float="ocaml_low_add_byte""ocaml_low_add"[@@unboxed]external(-.):float->float->float="ocaml_low_sub_byte""ocaml_low_sub"[@@unboxed]external(*.):float->float->float="ocaml_low_mul_byte""ocaml_low_mul"[@@unboxed]external(/.):float->float->float="ocaml_low_div_byte""ocaml_low_div"[@@unboxed]let[@inline]sqrx=x*.x(* a·xⁿ for a ≥ 0, x ≥ 0 and n ∈ ℕ. *)letrecpos_pow_INaxn=ifn=0thenaelseifis_evennthenpos_pow_INa(x*.x)(n/2)elsepos_pow_IN(a*.x)(x*.x)(n/2)end(* Base [High] module. *)moduleH=structmoduleU=Interval__Utypet=floatletzero=0.letone=1.letpi=0x1.921fb54442d19p1lettwo_pi=0x1.921fb54442d19p2lethalf_pi=0x1.921fb54442d19p0lete=0x1.5bf0a8b14576Ap1externalfloat:(int[@untagged])->(float[@unboxed])="ocaml_high_float_byte""ocaml_high_float"external(+.):float->float->float="ocaml_high_add_byte""ocaml_high_add"[@@unboxed]external(-.):float->float->float="ocaml_high_sub_byte""ocaml_high_sub"[@@unboxed]external(*.):float->float->float="ocaml_high_mul_byte""ocaml_high_mul"[@@unboxed]external(/.):float->float->float="ocaml_high_div_byte""ocaml_high_div"[@@unboxed]let[@inline]sqrx=x*.x(* a·xⁿ for a ≥ 0, x ≥ 0 and n ∈ ℕ. *)letrecpos_pow_INaxn=ifn=0thenaelseifis_evennthenpos_pow_INa(x*.x)(n/2)elsepos_pow_IN(a*.x)(x*.x)(n/2)endlet[@inline]low_cbrx=ifx>=0.thenL.(x*.x*.x)elseL.(x*.H.(x*.x))let[@inline]high_cbrx=ifx>=0.thenH.(x*.x*.x)elseH.(x*.L.(x*.x))letreclow_pow_INxn=(* x ∈ ℝ, n ≥ 0 *)ifis_evennthenL.(pos_pow_IN1.(x*.x)(n/2))elseifx>=0.thenL.(pos_pow_INx(x*.x)(n/2))elseL.(x*.H.(pos_pow_IN1.(x*.x)(n/2)))andlow_pow_ix=function|0->1.|1->x|2->L.(x*.x)|3->low_cbrx|4->L.(letx2=x*.xinx2*.x2)|n->ifn>=0thenlow_pow_INxnelse(* Since the rounding has the same sign than xⁿ, we can
treat u ↦ 1/u as decreasing. *)L.(1./.high_pow_INx(-n))andhigh_pow_INxn=ifis_evennthenH.(pos_pow_IN1.(x*.x)(n/2))elseifx>=0.thenH.(pos_pow_INx(x*.x)(n/2))elseH.(x*.L.(pos_pow_IN1.(x*.x)(n/2)))andhigh_pow_ix=function|0->1.|1->x|2->H.(x*.x)|3->high_cbrx|4->H.(letx2=x*.xinx2*.x2)|n->ifn>=0thenhigh_pow_INxnelseH.(1./.low_pow_INx(-n))(* The [Low] and [High] modules below depend on both the previous
[Low0] and [High0]. *)moduleLow=structincludeLletcbr=low_cbr(* xⁿ for x ≤ 0 and n ≥ 0. Useful for the interval extension. *)let[@inline]neg_pow_INx=function|0->1.|1->x|2->x*.x|3->x*.H.(x*.x)|4->letx2=x*.xinx2*.x2|n->ifis_evennthenpos_pow_IN1.(x*.x)(n/2)elsex*.H.(pos_pow_IN1.(x*.x)(n/2))letpow_i=low_pow_iendmoduleHigh=structincludeHletcbr=high_cbr(* xⁿ for x ≤ 0 and n ≥ 0. Useful for the interval extension. *)let[@inline]neg_pow_INx=function|0->1.|1->x|2->x*.x|3->x*.L.(x*.x)|4->letx2=x*.xinx2*.x2|n->ifis_evennthenpos_pow_IN1.(x*.x)(n/2)elsex*.L.(pos_pow_IN1.(x*.x)(n/2))letpow_i=high_pow_iendmoduletypeDIRECTED=sigtypetvalzero:tvalone:tvalpi:tvaltwo_pi:tvalhalf_pi:tvale:tvalfloat:int->tval(+.):t->t->tval(-.):t->t->tval(*.):t->t->tval(/.):t->t->tvalsqr:t->tvalcbr:t->tvalpow_i:t->int->tendtypet={low:float;high:float}exceptionDivision_by_zeroexceptionDomain_errorofstringmoduleI=structtypenumber=floattypeinterval=ttypet=interval(* Invariants (enforced by [I.v]:
- -∞ ≤ low ≤ high ≤ +∞. In particular, no bound is NaN.
- [-∞,-∞] and [+∞,+∞] are not allowed. *)moduleU=Interval__U(* Save original operators *)letzero={low=0.;high=0.}letone={low=1.;high=1.}letentire={low=neg_infinity;high=infinity}letpi={low=Low.pi;high=High.pi}lettwo_pi={low=Low.two_pi;high=High.two_pi}lethalf_pi={low=Low.half_pi;high=High.half_pi}lete={low=Low.e;high=High.e}letv(a:float)(b:float)=ifa<b(* ⇒ a, b not NaN; most frequent case *)then{low=a;high=b}elseifa=bthenifa=neg_infinitytheninvalid_arg"Interval.I.v: [-inf, -inf] is not allowed"elseifa=infinitytheninvalid_arg"Interval.I.v: [+inf, +inf] is not allowed"else{low=a;high=b}else(* a > b or one of them is NaN *)invalid_arg("Interval.I.v: ["^string_of_floata^", "^string_of_floatb^"] not allowed")letlowi=i.lowlethighi=i.highletof_intn={low=Low.floatn;high=High.floatn}letto_string_fmtfmti=Printf.sprintf"[%(%f%), %(%f%)]"fmti.lowfmti.highletto_string?(fmt=("%g":_format))i=to_string_fmtfmtiletprchi=Printf.fprintfch"[%g, %g]"i.lowi.highletppfmti=Format.fprintffmt"[%g, %g]"i.lowi.highletfmtfmt_float=letopenCamlinternalFormatBasicsinletto_string()i=to_string_fmtfmt_floatiinletfmt=Custom(Custom_succCustom_zero,to_string,End_of_format)inFormat(fmt,"Inverval.t")letcompare_f{low=a;high=b}x=ifb<xthen1elseifa<=xthen0else-1letis_bounded{low;high}=neg_infinity<low&&high<infinityletis_entire{low;high}=neg_infinity=low&&high=infinityletequal{low=a;high=b}{low=c;high=d}=a=c&&b=dletsubset{low=a;high=b}{low=c;high=d}=(* No empty intervals. *)c<=a&&b<=dletless{low=a;high=b}{low=c;high=d}=a<=c&&b<=dletprecedesxy=x.high<=y.low(* intervals are not empty *)letinterior{low=a;high=b}{low=c;high=d}=(* Intervals are not empty *)(c<a||(c=neg_infinity&&a=neg_infinity))&&(b<d||(b=infinity&&d=infinity))letstrict_less{low=a;high=b}{low=c;high=d}=(* Intervals are not empty *)(a<c||(a=neg_infinity&&c=neg_infinity))&&(b<d||(b=infinity&&d=infinity))letstrict_precedesxy=x.high<y.low(* intervals not empty *)letdisjoint{low=a;high=b}{low=c;high=d}=(* Intervals are not empty *)b<c||d<aletwidthx={low=Low.(x.high-.x.low);high=High.(x.high-.x.low)}letwidth_lowx=Low.(x.high-.x.low)letwidth_highx=High.(x.high-.x.low)letsize=widthletsize_low=width_lowletsize_high=width_highletmagx=fmax(abs_floatx.low)(abs_floatx.high)letmigx=ifx.low>=0.thenx.lowelseifx.high<=0.then-.x.highelse(* x.low < 0 < x.high *)0.letabs({low=a;high=b}asx)=if0.<=athenxelseifb<=0.then{low=-.b;high=-.a}else{low=0.;high=fmax(-.a)b}letsgn{low=a;high=b}={low=float(comparea0.);high=float(compareb0.)}lettruncatex={low=floorx.low;high=ceilx.high}lethullxy={low=fminx.lowy.low;high=fmaxx.highy.high}letinter_exn{low=a;high=b}{low=c;high=d}=letlow=fmaxacinlethigh=fminbdiniflow<=highthen{low;high}elseraise(Domain_error"I.inter_exn")letinter{low=a;high=b}{low=c;high=d}=letlow=fmaxacinlethigh=fminbdiniflow<=highthenSome{low;high}elseNoneletmaxxy={low=fmaxx.lowy.low;high=fmaxx.highy.high}letminxy={low=fminx.lowy.low;high=fminx.highy.high}let(+){low=a;high=b}{low=c;high=d}={low=Low.(a+.c);high=High.(b+.d)}let(-){low=a;high=b}{low=c;high=d}={low=Low.(a-.d);high=High.(b-.c)}let(+.){low=a;high=b}x={low=Low.(a+.x);high=High.(b+.x)}let(+:)x{low=a;high=b}={low=Low.(a+.x);high=High.(b+.x)}let(-.){low=a;high=b}x={low=Low.(a-.x);high=High.(b-.x)}let(-:)x{low=c;high=d}={low=Low.(x-.d);high=High.(x-.c)}let(~-){low=a;high=b}={low=-.b;high=-.a}let(*){low=a;high=b}{low=c;high=d}=letsa=comparea0.andsb=compareb0.inletsc=comparec0.andsd=compared0.inif(sa=0&&sb=0)||(sc=0&&sd=0)then{low=0.;high=0.}elseifsb<=0thenifsd<=0then{low=Low.(b*.d);high=High.(a*.c)}elseif0<=scthen{low=Low.(a*.d);high=High.(b*.c)}else{low=Low.(a*.d);high=High.(a*.c)}elseif0<=sathenifsd<=0then{low=Low.(b*.c);high=High.(a*.d)}elseif0<=scthen{low=Low.(a*.c);high=High.(b*.d)}else{low=Low.(b*.c);high=High.(b*.d)}elseif0<=scthen{low=Low.(a*.d);high=High.(b*.d)}elseifsd<=0then{low=Low.(b*.c);high=High.(a*.c)}else{low=fminLow.(a*.d)Low.(b*.c);high=fmaxHigh.(a*.c)High.(b*.d)}let(*.)y{low=a;high=b}=letsy=comparey0.inifsy=0then{low=0.;high=0.}elseifsy<0then{low=Low.(b*.y);high=High.(a*.y)}else{low=Low.(a*.y);high=High.(b*.y)}let(*:)ay=y*.alet(/){low=a;high=b}{low=c;high=d}=letsc=comparec0.andsd=compared0.inifsd=0thenifsc=0thenraiseDivision_by_zeroelseifb<=0.then{low=Low.(b/.c);high=ifa=0.then0.elseinfinity}elseif0.<=athen{low=neg_infinity;high=High.(a/.c)}else{low=neg_infinity;high=infinity}elseifsd<0then{low=ifb<=0.thenLow.(b/.c)elseLow.(b/.d);high=if0.<=athenHigh.(a/.c)elseHigh.(a/.d)}elseifsc=0thenifb<=0.then{low=ifa=0.then0.elseneg_infinity;high=High.(b/.d)}elseif0.<=athen{low=Low.(a/.d);high=infinity}else{low=neg_infinity;high=infinity}elseif0<scthen{low=ifa<=0.thenLow.(a/.c)elseLow.(a/.d);high=ifb<=0.thenHigh.(b/.d)elseHigh.(b/.c)}elseifa=0.&&b=0.then{low=0.;high=0.}else{low=neg_infinity;high=infinity}let(/.){low=a;high=b}y=letsy=comparey0.inifsy=0thenraiseDivision_by_zeroelseif0<sythen{low=Low.(a/.y);high=High.(b/.y)}else{low=Low.(b/.y);high=High.(a/.y)}let(/:)x{low=a;high=b}=letsx=comparex0.andsa=comparea0.andsb=compareb0.inifsx=0thenifsa=0&&sb=0thenraiseDivision_by_zeroelse{low=0.;high=0.}elseif0<sa||sb<0thenif0<sxthen{low=Low.(x/.b);high=High.(x/.a)}else{low=Low.(x/.a);high=High.(x/.b)}elseifsa=0thenifsb=0thenraiseDivision_by_zeroelseif0<=sxthen{low=Low.(x/.b);high=infinity}else{low=neg_infinity;high=High.(x/.b)}elseifsb=0thenifsx=0then{low=0.;high=0.}elseif0<=sxthen{low=neg_infinity;high=High.(x/.a)}else{low=Low.(x/.a);high=infinity}else{low=neg_infinity;high=infinity}letinv{low=a;high=b}=letsa=comparea0.andsb=compareb0.inifsa=0thenifsb=0thenraiseDivision_by_zeroelse{low=Low.(1./.b);high=infinity}elseif0<sa||sb<0then{low=Low.(1./.b);high=High.(1./.a)}elseifsb=0then{low=neg_infinity;high=High.(1./.a)}else{low=neg_infinity;high=infinity}type'aone_or_two=Oneof'a|Twoof'a*'aletinvx{low=a;high=b}=letsa=comparea0.andsb=compareb0.inifsa=0thenifsb=0thenraiseDivision_by_zeroelseOne{low=Low.(1./.b);high=infinity}elseif0<sa||sb<0thenOne{low=Low.(1./.b);high=High.(1./.a)}elseifsb=0thenOne{low=neg_infinity;high=High.(1./.a)}elseTwo({low=neg_infinity;high=High.(1./.a)},{low=Low.(1./.b);high=infinity})letcancelminusxy=(* Intervals here cannot be empty. *)ifis_boundedx&&is_boundedythenletlow=Low.(x.low-.y.low)inlethigh=High.(x.high-.y.high)iniflow<=high(* thus not NaN *)then{low;high}elseentireelseentireletcancelplusxy=(* = cancelminus x (-y) *)ifis_boundedx&&is_boundedythenletlow=Low.(x.low+.y.high)inlethigh=High.(x.high+.y.low)iniflow<=high(* thus not NaN *)then{low;high}elseentireelseentireletsqr{low=a;high=b}=ifa>=0.then{low=Low.(a*.a);high=High.(b*.b)}else(* a < 0; a is not NaN *)ifb>=0.then{low=0.;high=fmaxHigh.(a*.a)High.(b*.b)}else{low=Low.(b*.b);high=High.(a*.a)}letcbr{low=a;high=b}={low=Low.cbra;high=High.cbrb}letpow_INx=function|0->one|1->x|2->sqrx|3->cbrx|n->(* n ≥ 0 assumed *)ifis_evennthenifx.low>=0.then{low=Low.pos_pow_IN1.x.lown;high=High.pos_pow_IN1.x.highn}elseifx.high>0.then(* x.low < 0 < x.high *){low=0.;high=fmaxHigh.(neg_pow_INx.lown)High.(pos_pow_IN1.x.highn)}else(* x.low ≤ x.high ≤ 0 *){low=Low.neg_pow_INx.highn;high=High.neg_pow_INx.lown}else(* x ↦ xⁿ is increasing. *){low=Low.pow_ix.lown;high=High.pow_ix.highn}let(**)xn=ifn>=0thenpow_INxnelseinv(pow_INxU.(-n))(* Infix aliases *)let(=)=equallet(<=)=lesslet(<)=strict_lesslet(>=)xy=lessyxlet(>)xy=strict_lessyxendexternalset_low:unit->unit="ocaml_set_low"[@@noalloc]externalset_high:unit->unit="ocaml_set_high"[@@noalloc]externalset_nearest:unit->unit="ocaml_set_nearest"[@@noalloc]