├── .gitignore ├── .travis.yml ├── docs ├── index_classes.html ├── index_exceptions.html ├── index_extensions.html ├── index_class_types.html ├── index_methods.html ├── index_module_types.html ├── index_attributes.html ├── index_modules.html ├── index_types.html ├── index.html ├── style.css ├── type_Interval2.html ├── type_Interval1.html ├── Interval2.html └── Interval1.html ├── Makefile ├── LICENSE ├── tests ├── Makefile ├── t_test_interval.ml ├── log2.txt ├── log2_opt.txt ├── log1.txt ├── log1_opt.txt ├── p_interval2.ml ├── p_interval1.ml ├── test.ml └── test_interval.ml ├── README.md ├── interval1.mli ├── interval2.mli ├── interval1.ml └── interval2.ml /.gitignore: -------------------------------------------------------------------------------- 1 | *.annot 2 | *.cmo 3 | *.cma 4 | *.cmi 5 | *.a 6 | *.o 7 | *.cmx 8 | *.cmxs 9 | *.cmxa 10 | 11 | # ocamlbuild working directory 12 | _build/ 13 | 14 | # ocamlbuild targets 15 | *.byte 16 | *.native 17 | 18 | # oasis generated files 19 | setup.data 20 | setup.log 21 | 22 | # tmp 23 | *~ 24 | a.out 25 | 26 | # other 27 | p_interval1 28 | p_interval1_opt 29 | p_interval2 30 | p_interval2_opt 31 | t_interval1 32 | t_interval1_opt 33 | t_interval2 34 | t_interval2_opt -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: required 3 | env: 4 | global: 5 | - TEST_SAMPLES=500 6 | - INSTALL_XQUARTZ=false 7 | matrix: 8 | - OCAML_VERSION=4.00 9 | - OCAML_VERSION=4.01 10 | - OCAML_VERSION=4.02 11 | - OCAML_VERSION=4.04 12 | - OCAML_VERSION=4.05 13 | os: 14 | - linux 15 | - osx 16 | git: 17 | depth: 1 18 | before_install: 19 | - wget https://raw.githubusercontent.com/ocaml/ocaml-ci-scripts/master/.travis-ocaml.sh 20 | install: 21 | - sh .travis-ocaml.sh 22 | script: 23 | - make test 24 | -------------------------------------------------------------------------------- /docs/index_classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of classes 12 | 13 | 14 | 16 |

Index of classes

17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /docs/index_exceptions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of exceptions 12 | 13 | 14 | 16 |

Index of exceptions

17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /docs/index_extensions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of extensions 12 | 13 | 14 | 16 |

Index of extensions

17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /docs/index_class_types.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of class types 12 | 13 | 14 | 16 |

Index of class types

17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /docs/index_methods.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of class methods 12 | 13 | 14 | 16 |

Index of class methods

17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /docs/index_module_types.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of module types 12 | 13 | 14 | 16 |

Index of module types

17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /docs/index_attributes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of class attributes 12 | 13 | 14 | 16 |

Index of class attributes

17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ML = ocamlc 2 | OPT_ML = ocamlopt 3 | 4 | SRC= interval1.mli\ 5 | interval1.ml\ 6 | interval2.mli\ 7 | interval2.ml 8 | 9 | OBJ_BYTE0 = $(SRC:.ml=.cmo) 10 | OBJ_BYTE = $(OBJ_BYTE0:.mli=.cmi) 11 | 12 | OBJ_NATIVE = $(OBJ_BYTE:.cmo=.cmx) 13 | 14 | .PHONY: all docs test clean 15 | 16 | all: interval.cma interval.cmxa 17 | 18 | docs: interval1.mli interval2.mli 19 | mkdir -p docs 20 | ocamldoc -d docs -html interval1.mli interval2.mli 21 | 22 | test: interval.cma interval.cmxa 23 | cd tests; $(MAKE) 24 | 25 | interval.cma: $(OBJ_BYTE) 26 | $(ML) -a -o interval.cma $(OBJ_BYTE0) 27 | 28 | interval.cmxa: $(OBJ_NATIVE) 29 | $(OPT_ML) -a -o interval.cmxa $(OBJ_BYTE0:.cmo=.cmx) 30 | 31 | %.cmi : %.mli 32 | $(ML) -c $^ 33 | 34 | %.cmo : %.ml 35 | $(ML) -c $^ 36 | 37 | %.cmx : %.ml 38 | $(OPT_ML) -c $^ 39 | 40 | clean: 41 | rm -f *.cmo *.cmi *.cmx *.cma *.cmxa *.o *.a 42 | cd tests; $(MAKE) clean 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Alexey Solovyev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/index_modules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of modules 12 | 13 | 14 | 16 |

Index of modules

17 | 18 | 19 | 20 | 24 | 25 | 29 |

I
Interval1
21 | A simple OCaml interval library. 22 |
23 |
Interval2
26 | A simple OCaml interval library. 27 |
28 |
30 | 31 | -------------------------------------------------------------------------------- /docs/index_types.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index of types 12 | 13 | 14 | 16 |

Index of types

17 | 18 | 19 | 20 | 24 | 25 | 29 |

I
interval [Interval2]
21 | The interval type 22 |
23 |
interval [Interval1]
26 | The interval type 27 |
28 |
30 | 31 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 | 21 |

22 | 23 | 27 | 31 |
Interval1
24 | A simple OCaml interval library. 25 |
26 |
Interval2
28 | A simple OCaml interval library. 29 |
30 |
32 | 33 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | all: t_interval1 t_interval1_opt t_interval2 t_interval2_opt 2 | ./t_interval1 3 | ./t_interval1_opt 4 | ./t_interval2 5 | ./t_interval2_opt 6 | 7 | t_interval1: 8 | ocamlc -o t_interval1 -I .. nums.cma unix.cma \ 9 | ../interval1.ml test_interval.ml test.ml t_interval1.ml 10 | ocamlc -o p_interval1 -I .. unix.cma \ 11 | ../interval1.ml test.ml p_interval1.ml 12 | 13 | t_interval1_opt: 14 | ocamlopt -o t_interval1_opt -I .. nums.cmxa unix.cmxa \ 15 | ../interval1.ml test_interval.ml test.ml t_interval1.ml 16 | ocamlopt -o p_interval1_opt -I .. unix.cmxa \ 17 | ../interval1.ml test.ml p_interval1.ml 18 | 19 | t_interval2: 20 | ocamlc -o t_interval2 -I .. nums.cma unix.cma \ 21 | ../interval2.ml test_interval.ml test.ml t_interval2.ml 22 | ocamlc -o p_interval2 -I .. nums.cma unix.cma \ 23 | ../interval2.ml test.ml p_interval2.ml 24 | 25 | t_interval2_opt: 26 | ocamlopt -o t_interval2_opt -I .. nums.cmxa unix.cmxa \ 27 | ../interval2.ml test_interval.ml test.ml t_interval2.ml 28 | ocamlopt -o p_interval2_opt -I .. nums.cmxa unix.cmxa \ 29 | ../interval2.ml test.ml p_interval2.ml 30 | 31 | t_interval_tmp: 32 | ocamlc -o t_interval_tmp -I .. nums.cma unix.cma \ 33 | ../interval_tmp.ml test_interval.ml test.ml t_interval_tmp.ml 34 | 35 | t_interval_tmp_opt: 36 | ocamlopt -o t_interval_tmp_opt -I .. nums.cmxa unix.cmxa \ 37 | ../interval_tmp.ml test_interval.ml test.ml t_interval_tmp.ml 38 | 39 | clean: 40 | rm -f *.cmo *.cmi *.cmx *.o \ 41 | t_interval1 t_interval2 t_interval_tmp \ 42 | p_interval1 p_interval2 p_interval_tmp \ 43 | t_interval1_opt t_interval2_opt t_interval_tmp_opt \ 44 | p_interval1_opt p_interval2_opt p_interval_tmp_opt 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/monadius/ocaml_simple_interval.svg?branch=master)](https://travis-ci.org/monadius/ocaml_simple_interval) 2 | 3 | # ocaml_simple_interval 4 | A simple and (hopefully) portable floating-point interval arithmetic library in OCaml. 5 | 6 | Original repository: [https://github.com/monadius/ocaml_simple_interval](https://github.com/monadius/ocaml_simple_interval) 7 | 8 | ## References 9 | 10 | - S. Rump, P. Zimmermann, S. Boldo, G. Melquiond 11 | [*Computing predecessor and successor in rounding to nearest*](https://hal.inria.fr/inria-00337537/document) 12 | [(link2)](http://www.ti3.tuhh.de/paper/rump/RuZiBoMe09.pdf) 13 | 14 | - S. Rump, T. Ogita, Y. Morikura, S. Oishi 15 | [*Interval arithmetic with fixed rounding mode*](https://www.jstage.jst.go.jp/article/nolta/7/3/7_362/_pdf) 16 | 17 | - F. Goualard 18 | [*How do you compute the midpoint of an interval?*](https://hal.archives-ouvertes.fr/hal-00576641/document) 19 | 20 | - [*ValidatedNumerics.jl*](https://github.com/dpsanders/ValidatedNumerics.jl) 21 | 22 | - [*Java library for interval computations*](https://java.net/projects/jinterval) 23 | 24 | - S. Boldo, 25 | [*Dekker algorithm: error of the multiplication*](https://www.lri.fr/~sboldo/progs/Dekker.c.html). 26 | See also S. Boldo, C. Marché, 27 | [*Formal verification of numerical programs: from C annotated programs to mechanical proofs*](https://hal.inria.fr/hal-00777605/document) 28 | 29 | # Interval1 30 | 31 | [`Interval1`](interval1.mli) is a simple OCaml interval arithmetic 32 | library which does not depend on any external files and libraries. It 33 | uses the standard rounding to nearest floating-point operations to 34 | compute rigorous interval enclosures of mathematical operations. These 35 | interval enclosures may be not optimal floating-point intervals but in 36 | most cases the error is no more than 1 ulp for each interval endpoint. 37 | 38 | # Interval2 39 | 40 | [`Interval2`](interval2.mli) is another simple OCaml interval 41 | arithmetic library. It computes optimal floating-point intervals for 42 | basic arithmetic operations. In some cases, it performs computations 43 | with rational arithmetic. This library is slower than `Interval1` but 44 | it may be used in cases when optimal intervals are required (for 45 | instance, when point intervals play an important role or when 46 | discontinuous functions are considered). 47 | 48 | # Docs 49 | 50 | See the [docs](docs) directory. 51 | 52 | # Tests 53 | 54 | See the [tests](tests) directory. 55 | -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | .keyword { font-weight : bold ; color : Red } 2 | .keywordsign { color : #C04600 } 3 | .superscript { font-size : 4 } 4 | .subscript { font-size : 4 } 5 | .comment { color : Green } 6 | .constructor { color : Blue } 7 | .type { color : #5C6585 } 8 | .string { color : Maroon } 9 | .warning { color : Red ; font-weight : bold } 10 | .info { margin-left : 3em; margin-right: 3em } 11 | .param_info { margin-top: 4px; margin-left : 3em; margin-right : 3em } 12 | .code { color : #465F91 ; } 13 | .typetable { border-style : hidden } 14 | .paramstable { border-style : hidden ; padding: 5pt 5pt} 15 | tr { background-color : White } 16 | td.typefieldcomment { background-color : #FFFFFF ; font-size: smaller ;} 17 | div.sig_block {margin-left: 2em} 18 | *:target { background: yellow; } 19 | body {font: 13px sans-serif; color: black; text-align: left; padding: 5px; margin: 0} 20 | h1 { font-size : 20pt ; text-align: center; } 21 | h2 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90BDFF ;padding: 2px; } 22 | h3 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90DDFF ;padding: 2px; } 23 | h4 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90EDFF ;padding: 2px; } 24 | h5 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90FDFF ;padding: 2px; } 25 | h6 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90BDFF ; padding: 2px; } 26 | div.h7 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #E0FFFF ; padding: 2px; } 27 | div.h8 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #F0FFFF ; padding: 2px; } 28 | div.h9 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #FFFFFF ; padding: 2px; } 29 | a {color: #416DFF; text-decoration: none} 30 | a:hover {background-color: #ddd; text-decoration: underline} 31 | pre { margin-bottom: 4px; font-family: monospace; } 32 | pre.verbatim, pre.codepre { } 33 | .indextable {border: 1px #ddd solid; border-collapse: collapse} 34 | .indextable td, .indextable th {border: 1px #ddd solid; min-width: 80px} 35 | .indextable td.module {background-color: #eee ; padding-left: 2px; padding-right: 2px} 36 | .indextable td.module a {color: 4E6272; text-decoration: none; display: block; width: 100%} 37 | .indextable td.module a:hover {text-decoration: underline; background-color: transparent} 38 | .deprecated {color: #888; font-style: italic} 39 | .indextable tr td div.info { margin-left: 2px; margin-right: 2px } 40 | ul.indexlist { margin-left: 0; padding-left: 0;} 41 | ul.indexlist li { list-style-type: none ; margin-left: 0; padding-left: 0; } -------------------------------------------------------------------------------- /tests/t_test_interval.ml: -------------------------------------------------------------------------------- 1 | open Num 2 | open Test 3 | open Test_interval 4 | 5 | (* let () = Random.self_init () *) 6 | 7 | let samples = 1000 8 | 9 | (* next_float tests *) 10 | 11 | let test_next_float x = 12 | let y = next_float x in 13 | ignore begin 14 | match classify_float x with 15 | | FP_nan -> 16 | fact ("nan", is_nan y) 17 | | FP_infinite -> 18 | if x = neg_infinity then 19 | fact ("neg_infinity", is_nan y) 20 | else 21 | fact ("infinity", y = infinity) 22 | | FP_zero | FP_normal | FP_subnormal -> 23 | let d = y -. x in 24 | fact ("mono", y > x); 25 | fact ("pos", d > 0.0); 26 | fact ("eq", x +. d = y); 27 | if x < max_float then fact ("small", x +. d *. 0.25 = x); 28 | end; 29 | true 30 | 31 | let () = 32 | let eta_float = ldexp 1.0 (-1074) in 33 | (* Tests with special values *) 34 | run_eq_f "next_float (eq)" next_float [ 35 | -.0.0, eta_float; 36 | 0.0, eta_float; 37 | min_float, min_float +. eta_float; 38 | min_float -. eta_float, min_float; 39 | -.min_float, -.(min_float -. eta_float); 40 | eta_float, 2.0 *. eta_float; 41 | -.eta_float, 0.0; 42 | 1.0, 1.0 +. epsilon_float; 43 | 1.0 -. epsilon_float *. 0.5, 1.0; 44 | -1.0, -.(1.0 -. epsilon_float *. 0.5); 45 | max_float, infinity; 46 | infinity, infinity; 47 | nan, nan; 48 | neg_infinity, nan; 49 | ]; 50 | 51 | (* Tests with special data *) 52 | run_test (test_f "next_float (special)" test_next_float) 53 | (special_data_f ()); 54 | 55 | (* Tests with randomly generated data *) 56 | run_test (test_f "next_float" test_next_float) 57 | (standard_data_f ~n:samples ~sign:0) 58 | 59 | (* prev_float tests *) 60 | 61 | let test_prev_float x = 62 | let y = prev_float x in 63 | ignore begin 64 | match classify_float x with 65 | | FP_nan -> 66 | fact ("nan", is_nan y) 67 | | FP_infinite -> 68 | if x = neg_infinity then 69 | fact ("neg_infinity", y = neg_infinity) 70 | else 71 | fact ("infinity", is_nan y) 72 | | FP_zero | FP_normal | FP_subnormal -> 73 | let d = x -. y in 74 | fact ("mono", y < x); 75 | fact ("positive", d > 0.0); 76 | fact ("eq", x -. d = y); 77 | if x > -.max_float then fact ("small", x -. d *. 0.25 = x); 78 | end; 79 | true 80 | 81 | let () = 82 | let eta_float = ldexp 1.0 (-1074) in 83 | (* Tests with special values *) 84 | run_eq_f "prev_float (eq)" prev_float [ 85 | -.0.0, -.eta_float; 86 | 0.0, -.eta_float; 87 | min_float, min_float -. eta_float; 88 | min_float +. eta_float, min_float; 89 | -.min_float, -.(min_float +. eta_float); 90 | eta_float, 0.0; 91 | -.eta_float, -2.0 *. eta_float; 92 | 1.0, 1.0 -. 0.5 *. epsilon_float; 93 | 1.0 -. epsilon_float *. 0.5, 1.0 -. epsilon_float; 94 | -1.0, -.(1.0 +. epsilon_float); 95 | -.max_float, neg_infinity; 96 | infinity, nan; 97 | nan, nan; 98 | neg_infinity, neg_infinity; 99 | ]; 100 | 101 | (* Tests with special data *) 102 | run_test (test_f "prev_float (special)" test_prev_float) 103 | (special_data_f ()); 104 | 105 | (* Tests with randomly generated data *) 106 | run_test (test_f "prev_float" test_prev_float) 107 | (standard_data_f ~n:samples ~sign:0) 108 | 109 | (* num_of_float and float_of_num_lo(hi) tests *) 110 | 111 | let test_num_float x = 112 | let r = num_of_float x in 113 | let r1 = Num.pred_num r and 114 | r2 = Num.succ_num r in 115 | let a = float_of_num_lo r and 116 | b = float_of_num_hi r and 117 | a1 = float_of_num_lo r1 and 118 | b1 = float_of_num_hi r1 and 119 | a2 = float_of_num_lo r2 and 120 | b2 = float_of_num_hi r2 in 121 | ignore begin 122 | fact ("eq", a = x && b = x); 123 | fact ("le", a1 < x && b1 <= x); 124 | fact ("ge", a2 >= x && b2 > x); 125 | if b1 = x then fact ("eq_prev", a1 = prev_float x); 126 | if a2 = x then fact ("eq_next", b2 = next_float x); 127 | end; 128 | true 129 | 130 | let () = 131 | let eta_float = ldexp 1.0 (-1074) in 132 | (* Tests with special values *) 133 | run_eq_f "num_of_float (eq)" ~cmp:compare_num num_of_float [ 134 | -.0.0, Int 0; 135 | 0.0, Int 0; 136 | eta_float, Int 2 **/ Int (-1074); 137 | -2.0 *. eta_float, Int (-2) **/ Int (-1073); 138 | 1.0, Int 1; 139 | -1.5, Int (-3) // Int 2; 140 | ]; 141 | 142 | (* Tests with randomly generated data *) 143 | run_test (test_f "test_num_float" test_num_float) 144 | (standard_data_f ~n:samples ~sign:0) 145 | -------------------------------------------------------------------------------- /tests/log2.txt: -------------------------------------------------------------------------------- 1 | benchmark samples n mean sigma overhead 2 | empty 10000 10 0.00028 0.00007 0.00028 3 | empty2 10000 10 0.00044 0.00005 0.00044 4 | fsucc 10000 10 0.00054 0.00002 0.00026 5 | fpred 10000 10 0.00072 0.00037 0.00044 6 | +. 10000 10 0.00046 0.00003 0.00046 7 | fadd_low 10000 10 0.00103 0.00012 0.00057 8 | fadd_high 10000 10 0.00098 0.00000 0.00051 9 | -. 10000 10 0.00046 0.00003 0.00046 10 | fsub_low 10000 10 0.00111 0.00001 0.00065 11 | fsub_high 10000 10 0.00113 0.00009 0.00067 12 | *. 10000 10 0.00047 0.00006 0.00047 13 | fmul_low 10000 10 0.00270 0.00017 0.00223 14 | fmul_high 10000 10 0.00271 0.00007 0.00224 15 | /. 10000 10 0.00045 0.00000 0.00045 16 | fdiv_low 10000 10 0.00395 0.00005 0.00350 17 | fdiv_high 10000 10 0.00394 0.00006 0.00349 18 | sqr 10000 10 0.00031 0.00002 0.00031 19 | fsqr_low 10000 10 0.00171 0.00006 0.00141 20 | fsqr_high 10000 10 0.00181 0.00004 0.00150 21 | sqrt 10000 10 0.00027 0.00000 0.00027 22 | fsqrt_low 10000 10 0.00233 0.00013 0.00206 23 | fsqrt_high 10000 10 0.00226 0.00003 0.00198 24 | exp 10000 10 0.00039 0.00000 0.00039 25 | fexp_low 10000 10 0.00078 0.00011 0.00039 26 | fexp_high 10000 10 0.00070 0.00000 0.00031 27 | log 10000 10 0.00034 0.00001 0.00034 28 | flog_low 10000 10 0.00079 0.00001 0.00045 29 | flog_high 10000 10 0.00079 0.00002 0.00045 30 | atan 10000 10 0.00056 0.00000 0.00056 31 | fatan_low 10000 10 0.00094 0.00001 0.00038 32 | fatan_high 10000 10 0.00099 0.00013 0.00044 33 | x^2 10000 10 0.00065 0.00004 0.00065 34 | fpown_low(2) 10000 10 0.00194 0.00017 0.00130 35 | fpown_high(2) 10000 10 0.00205 0.00014 0.00140 36 | x^3 10000 10 0.00064 0.00001 0.00064 37 | fpown_low(3) 10000 10 0.93770 0.00180 0.93706 38 | fpown_high(3) 10000 10 0.94191 0.01058 0.94126 39 | x^(-2) 10000 10 0.00066 0.00003 0.00066 40 | fpown_low(-2) 10000 10 0.79430 0.00121 0.79364 41 | fpown_high(-2) 10000 10 0.80409 0.00103 0.80344 42 | x^(-3) 10000 10 0.00064 0.00001 0.00064 43 | fpown_low(-3) 10000 10 0.97141 0.00189 0.97077 44 | fpown_high(-3) 10000 10 0.97558 0.00796 0.97494 45 | 46 | benchmark samples n mean sigma overhead 47 | empty 10000 10 0.00022 0.00000 0.00022 48 | mid_i 10000 10 0.00071 0.00001 0.00049 49 | neg_i 10000 10 0.00042 0.00000 0.00020 50 | abs_i 10000 10 0.00095 0.00003 0.00073 51 | *test*: add_ii 10000 10 0.00067 0.00001 0.00067 52 | add_ii 10000 10 0.00243 0.00004 0.00176 53 | add_id 10000 10 0.00215 0.00005 0.00148 54 | add_di 10000 10 0.00219 0.00011 0.00151 55 | *test*: sub_ii 10000 10 0.00067 0.00002 0.00067 56 | sub_ii 10000 10 0.00288 0.00002 0.00220 57 | sub_id 10000 10 0.00261 0.00003 0.00194 58 | sub_di 10000 10 0.00263 0.00005 0.00196 59 | *test*: mul_ii 10000 10 0.00082 0.00005 0.00082 60 | mul_ii 10000 10 0.00811 0.00017 0.00728 61 | mul_id 10000 10 0.00590 0.00003 0.00507 62 | mul_di 10000 10 0.00593 0.00005 0.00511 63 | *test*: div_ii 10000 10 0.00069 0.00003 0.00069 64 | div_ii 10000 10 0.00515 0.00003 0.00446 65 | div_id 10000 10 0.00821 0.00006 0.00752 66 | div_di 10000 10 0.00577 0.00022 0.00507 67 | *test*: inv_i 10000 10 0.00050 0.00010 0.00050 68 | inv_i 10000 10 0.00445 0.00017 0.00395 69 | *test*: sqr_i 10000 10 0.00045 0.00001 0.00045 70 | sqr_i 10000 10 0.00348 0.00005 0.00303 71 | *test*: sqrt_i 10000 10 0.00042 0.00000 0.00042 72 | sqrt_i 10000 10 0.00412 0.00017 0.00371 73 | *test*: exp_i 10000 10 0.00061 0.00001 0.00061 74 | exp_i 10000 10 0.00167 0.00017 0.00106 75 | *test*: log_i 10000 10 0.00058 0.00001 0.00058 76 | log_i 10000 10 0.00178 0.00002 0.00119 77 | *test*: atan_i 10000 10 0.00085 0.00000 0.00085 78 | atan_i 10000 10 0.00194 0.00003 0.00110 79 | *test*: x^2 10000 10 0.00124 0.00003 0.00124 80 | pown_i(2) 10000 10 0.00404 0.00017 0.00280 81 | *test*: x^3 10000 10 0.00125 0.00005 0.00125 82 | pown_i(3) 10000 10 1.88934 0.00246 1.88809 83 | *test*: x^(-2) 10000 10 0.00125 0.00004 0.00125 84 | pown_i(-2) 10000 10 1.21381 0.01080 1.21256 85 | *test*: x^(-3) 10000 10 0.00124 0.00002 0.00124 86 | pown_i(-3) 10000 10 0.97121 0.00160 0.96997 87 | -------------------------------------------------------------------------------- /tests/log2_opt.txt: -------------------------------------------------------------------------------- 1 | benchmark samples n mean sigma overhead 2 | empty 10000 10 0.00004 0.00000 0.00004 3 | empty2 10000 10 0.00005 0.00000 0.00005 4 | fsucc 10000 10 0.00005 0.00000 0.00001 5 | fpred 10000 10 0.00005 0.00000 0.00001 6 | +. 10000 10 0.00006 0.00000 0.00006 7 | fadd_low 10000 10 0.00015 0.00001 0.00010 8 | fadd_high 10000 10 0.00016 0.00002 0.00010 9 | -. 10000 10 0.00005 0.00000 0.00005 10 | fsub_low 10000 10 0.00017 0.00000 0.00012 11 | fsub_high 10000 10 0.00017 0.00000 0.00012 12 | *. 10000 10 0.00005 0.00000 0.00005 13 | fmul_low 10000 10 0.00024 0.00000 0.00019 14 | fmul_high 10000 10 0.00025 0.00001 0.00020 15 | /. 10000 10 0.00005 0.00000 0.00005 16 | fdiv_low 10000 10 0.00050 0.00004 0.00044 17 | fdiv_high 10000 10 0.00048 0.00000 0.00043 18 | sqr 10000 10 0.00004 0.00000 0.00004 19 | fsqr_low 10000 10 0.00021 0.00000 0.00017 20 | fsqr_high 10000 10 0.00024 0.00005 0.00019 21 | sqrt 10000 10 0.00005 0.00001 0.00005 22 | fsqrt_low 10000 10 0.00037 0.00000 0.00033 23 | fsqrt_high 10000 10 0.00037 0.00000 0.00033 24 | exp 10000 10 0.00015 0.00000 0.00015 25 | fexp_low 10000 10 0.00019 0.00003 0.00004 26 | fexp_high 10000 10 0.00018 0.00000 0.00003 27 | log 10000 10 0.00011 0.00001 0.00011 28 | flog_low 10000 10 0.00015 0.00000 0.00004 29 | flog_high 10000 10 0.00015 0.00000 0.00004 30 | atan 10000 10 0.00024 0.00001 0.00024 31 | fatan_low 10000 10 0.00028 0.00001 0.00004 32 | fatan_high 10000 10 0.00028 0.00000 0.00004 33 | x^2 10000 10 0.00039 0.00000 0.00039 34 | fpown_low(2) 10000 10 0.00022 0.00000 -0.00017 35 | fpown_high(2) 10000 10 0.00022 0.00000 -0.00017 36 | x^3 10000 10 0.00041 0.00003 0.00041 37 | fpown_low(3) 10000 10 0.35867 0.00138 0.35827 38 | fpown_high(3) 10000 10 0.36483 0.01232 0.36442 39 | x^(-2) 10000 10 0.00039 0.00001 0.00039 40 | fpown_low(-2) 10000 10 0.27738 0.00095 0.27699 41 | fpown_high(-2) 10000 10 0.27783 0.00098 0.27744 42 | x^(-3) 10000 10 0.00039 0.00000 0.00039 43 | fpown_low(-3) 10000 10 0.37389 0.00139 0.37350 44 | fpown_high(-3) 10000 10 0.37358 0.00126 0.37319 45 | 46 | benchmark samples n mean sigma overhead 47 | empty 10000 10 0.00003 0.00000 0.00003 48 | mid_i 10000 10 0.00006 0.00000 0.00003 49 | neg_i 10000 10 0.00006 0.00000 0.00003 50 | abs_i 10000 10 0.00025 0.00003 0.00022 51 | *test*: add_ii 10000 10 0.00007 0.00001 0.00007 52 | add_ii 10000 10 0.00038 0.00001 0.00031 53 | add_id 10000 10 0.00035 0.00000 0.00028 54 | add_di 10000 10 0.00035 0.00000 0.00028 55 | *test*: sub_ii 10000 10 0.00007 0.00001 0.00007 56 | sub_ii 10000 10 0.00038 0.00001 0.00031 57 | sub_id 10000 10 0.00037 0.00000 0.00030 58 | sub_di 10000 10 0.00038 0.00004 0.00031 59 | *test*: mul_ii 10000 10 0.00007 0.00001 0.00007 60 | mul_ii 10000 10 0.00096 0.00002 0.00089 61 | mul_id 10000 10 0.00061 0.00000 0.00054 62 | mul_di 10000 10 0.00061 0.00002 0.00054 63 | *test*: div_ii 10000 10 0.00007 0.00001 0.00007 64 | div_ii 10000 10 0.00062 0.00012 0.00055 65 | div_id 10000 10 0.00094 0.00001 0.00087 66 | div_di 10000 10 0.00057 0.00001 0.00050 67 | *test*: inv_i 10000 10 0.00005 0.00000 0.00005 68 | inv_i 10000 10 0.00052 0.00011 0.00047 69 | *test*: sqr_i 10000 10 0.00005 0.00000 0.00005 70 | sqr_i 10000 10 0.00056 0.00000 0.00051 71 | *test*: sqrt_i 10000 10 0.00013 0.00001 0.00013 72 | sqrt_i 10000 10 0.00067 0.00001 0.00054 73 | *test*: exp_i 10000 10 0.00022 0.00000 0.00022 74 | exp_i 10000 10 0.00037 0.00000 0.00015 75 | *test*: log_i 10000 10 0.00024 0.00007 0.00024 76 | log_i 10000 10 0.00033 0.00000 0.00009 77 | *test*: atan_i 10000 10 0.00036 0.00000 0.00036 78 | atan_i 10000 10 0.00055 0.00001 0.00019 79 | *test*: x^2 10000 10 0.00066 0.00001 0.00066 80 | pown_i(2) 10000 10 0.00066 0.00012 0.00001 81 | *test*: x^3 10000 10 0.00066 0.00000 0.00066 82 | pown_i(3) 10000 10 0.71876 0.00126 0.71811 83 | *test*: x^(-2) 10000 10 0.00067 0.00003 0.00067 84 | pown_i(-2) 10000 10 0.41871 0.00139 0.41805 85 | *test*: x^(-3) 10000 10 0.00066 0.00000 0.00066 86 | pown_i(-3) 10000 10 0.37928 0.00830 0.37862 87 | -------------------------------------------------------------------------------- /tests/log1.txt: -------------------------------------------------------------------------------- 1 | benchmark samples n mean sigma overhead 2 | empty 1000000 10 0.02770 0.01043 0.02770 3 | empty2 1000000 10 0.03965 0.00064 0.03965 4 | fsucc 1000000 10 0.04742 0.00039 0.01972 5 | fpred 1000000 10 0.04763 0.00065 0.01993 6 | +. 1000000 10 0.04664 0.00057 0.04664 7 | fadd_low 1000000 10 0.09141 0.00053 0.04478 8 | fadd_high 1000000 10 0.09211 0.00067 0.04548 9 | -. 1000000 10 0.04602 0.00027 0.04602 10 | fsub_low 1000000 10 0.09171 0.00048 0.04569 11 | fsub_high 1000000 10 0.09224 0.00090 0.04623 12 | *. 1000000 10 0.04651 0.00038 0.04651 13 | fmul_low 1000000 10 0.10609 0.00047 0.05958 14 | fmul_high 1000000 10 0.10597 0.00044 0.05947 15 | /. 1000000 10 0.04671 0.00049 0.04671 16 | fdiv_low 1000000 10 0.09864 0.00109 0.05194 17 | fdiv_high 1000000 10 0.09883 0.00084 0.05213 18 | sqr 1000000 10 0.03016 0.00023 0.03016 19 | fsqr_low 1000000 10 0.07350 0.00057 0.04334 20 | fsqr_high 1000000 10 0.06525 0.00090 0.03509 21 | sqrt 1000000 10 0.02772 0.00016 0.02772 22 | fsqrt_low 1000000 10 0.07236 0.00051 0.04464 23 | fsqrt_high 1000000 10 0.06791 0.00986 0.04019 24 | exp 1000000 10 0.03974 0.00025 0.03974 25 | fexp_low 1000000 10 0.07603 0.00062 0.03629 26 | fexp_high 1000000 10 0.06985 0.00096 0.03011 27 | log 1000000 10 0.03424 0.00049 0.03424 28 | flog_low 1000000 10 0.07725 0.00059 0.04301 29 | flog_high 1000000 10 0.07723 0.00070 0.04299 30 | atan 1000000 10 0.05729 0.00041 0.05729 31 | fatan_low 1000000 10 0.09617 0.00062 0.03887 32 | fatan_high 1000000 10 0.09597 0.00070 0.03868 33 | x^2 1000000 10 0.06528 0.00070 0.06528 34 | fpown_low(2) 1000000 10 0.09409 0.00063 0.02881 35 | fpown_high(2) 1000000 10 0.08685 0.00045 0.02157 36 | x^3 1000000 10 0.06478 0.00051 0.06478 37 | fpown_low(3) 1000000 10 0.25235 0.00182 0.18756 38 | fpown_high(3) 1000000 10 0.24688 0.00102 0.18209 39 | x^(-2) 1000000 10 0.06585 0.00159 0.06585 40 | fpown_low(-2) 1000000 10 0.20540 0.00080 0.13955 41 | fpown_high(-2) 1000000 10 0.22608 0.00107 0.16023 42 | x^(-3) 1000000 10 0.06499 0.00057 0.06499 43 | fpown_low(-3) 1000000 10 0.35402 0.00129 0.28903 44 | fpown_high(-3) 1000000 10 0.34564 0.00095 0.28065 45 | 46 | benchmark samples n mean sigma overhead 47 | empty 1000000 10 0.02261 0.00021 0.02261 48 | mid_i_fast 1000000 10 0.04242 0.00044 0.01982 49 | mid_i 1000000 10 0.07288 0.00067 0.05028 50 | neg_i 1000000 10 0.04459 0.00028 0.02198 51 | abs_i 1000000 10 0.06943 0.00491 0.04682 52 | *test*: add_ii 1000000 10 0.06959 0.00054 0.06959 53 | add_ii 1000000 10 0.20975 0.00157 0.14017 54 | add_id 1000000 10 0.19837 0.00084 0.12878 55 | add_di 1000000 10 0.19624 0.00107 0.12665 56 | *test*: sub_ii 1000000 10 0.06976 0.00076 0.06976 57 | sub_ii 1000000 10 0.20970 0.00106 0.13993 58 | sub_id 1000000 10 0.20005 0.00236 0.13028 59 | sub_di 1000000 10 0.22009 0.00127 0.15033 60 | *test*: mul_ii 1000000 10 0.07037 0.00058 0.07037 61 | mul_ii 1000000 10 0.28831 0.00155 0.21794 62 | mul_id 1000000 10 0.25470 0.00146 0.18434 63 | mul_di 1000000 10 0.26183 0.00130 0.19147 64 | *test*: div_ii 1000000 10 0.06971 0.00097 0.06971 65 | div_ii 1000000 10 0.20905 0.00196 0.13935 66 | div_id 1000000 10 0.24034 0.00120 0.17064 67 | div_di 1000000 10 0.19208 0.00881 0.12237 68 | *test*: inv_i 1000000 10 0.04687 0.00052 0.04687 69 | inv_i 1000000 10 0.14517 0.00121 0.09830 70 | *test*: sqr_i 1000000 10 0.04652 0.00046 0.04652 71 | sqr_i 1000000 10 0.14969 0.00112 0.10316 72 | *test*: sqrt_i 1000000 10 0.04810 0.00045 0.04810 73 | sqrt_i 1000000 10 0.14025 0.00091 0.09215 74 | *test*: exp_i 1000000 10 0.06316 0.00070 0.06316 75 | exp_i 1000000 10 0.15119 0.00208 0.08803 76 | *test*: log_i 1000000 10 0.06766 0.00111 0.06766 77 | log_i 1000000 10 0.16333 0.00093 0.09567 78 | *test*: atan_i 1000000 10 0.08827 0.00072 0.08827 79 | atan_i 1000000 10 0.19972 0.00159 0.11146 80 | *test*: x^2 1000000 10 0.12782 0.00086 0.12782 81 | pown_i(2) 1000000 10 0.18920 0.00449 0.06138 82 | *test*: x^3 1000000 10 0.12798 0.00082 0.12798 83 | pown_i(3) 1000000 10 0.50952 0.00092 0.38153 84 | *test*: x^(-2) 1000000 10 0.12815 0.00104 0.12815 85 | pown_i(-2) 1000000 10 0.40901 0.00124 0.28086 86 | *test*: x^(-3) 1000000 10 0.12823 0.00086 0.12823 87 | pown_i(-3) 1000000 10 0.42399 0.00874 0.29576 88 | -------------------------------------------------------------------------------- /tests/log1_opt.txt: -------------------------------------------------------------------------------- 1 | benchmark samples n mean sigma overhead 2 | empty 1000000 10 0.00383 0.00009 0.00383 3 | empty2 1000000 10 0.00503 0.00040 0.00503 4 | fsucc 1000000 10 0.00490 0.00027 0.00107 5 | fpred 1000000 10 0.00496 0.00021 0.00113 6 | +. 1000000 10 0.00799 0.00083 0.00799 7 | fadd_low 1000000 10 0.01030 0.00058 0.00231 8 | fadd_high 1000000 10 0.01017 0.00028 0.00218 9 | -. 1000000 10 0.00800 0.00074 0.00800 10 | fsub_low 1000000 10 0.01009 0.00018 0.00209 11 | fsub_high 1000000 10 0.01006 0.00021 0.00206 12 | *. 1000000 10 0.00740 0.00004 0.00740 13 | fmul_low 1000000 10 0.01079 0.00035 0.00339 14 | fmul_high 1000000 10 0.01106 0.00023 0.00366 15 | /. 1000000 10 0.00757 0.00015 0.00757 16 | fdiv_low 1000000 10 0.01061 0.00006 0.00303 17 | fdiv_high 1000000 10 0.01072 0.00021 0.00315 18 | sqr 1000000 10 0.00419 0.00009 0.00419 19 | fsqr_low 1000000 10 0.00763 0.00011 0.00343 20 | fsqr_high 1000000 10 0.00686 0.00023 0.00267 21 | sqrt 1000000 10 0.00431 0.00021 0.00431 22 | fsqrt_low 1000000 10 0.00796 0.00025 0.00365 23 | fsqrt_high 1000000 10 0.00721 0.00026 0.00290 24 | exp 1000000 10 0.01539 0.00027 0.01539 25 | fexp_low 1000000 10 0.01853 0.00021 0.00313 26 | fexp_high 1000000 10 0.01782 0.00024 0.00242 27 | log 1000000 10 0.01156 0.00032 0.01156 28 | flog_low 1000000 10 0.01509 0.00034 0.00353 29 | flog_high 1000000 10 0.01504 0.00028 0.00348 30 | atan 1000000 10 0.02453 0.00021 0.02453 31 | fatan_low 1000000 10 0.02855 0.00043 0.00402 32 | fatan_high 1000000 10 0.02850 0.00041 0.00397 33 | x^2 1000000 10 0.03967 0.00078 0.03967 34 | fpown_low(2) 1000000 10 0.00990 0.00005 -0.02977 35 | fpown_high(2) 1000000 10 0.00891 0.00022 -0.03075 36 | x^3 1000000 10 0.03950 0.00041 0.03950 37 | fpown_low(3) 1000000 10 0.02555 0.00025 -0.01395 38 | fpown_high(3) 1000000 10 0.02537 0.00027 -0.01412 39 | x^(-2) 1000000 10 0.03946 0.00045 0.03946 40 | fpown_low(-2) 1000000 10 0.01822 0.00026 -0.02124 41 | fpown_high(-2) 1000000 10 0.02179 0.00029 -0.01768 42 | x^(-3) 1000000 10 0.03970 0.00068 0.03970 43 | fpown_low(-3) 1000000 10 0.03315 0.00033 -0.00655 44 | fpown_high(-3) 1000000 10 0.03388 0.00032 -0.00582 45 | 46 | benchmark samples n mean sigma overhead 47 | empty 1000000 10 0.00301 0.00005 0.00301 48 | mid_i_fast 1000000 10 0.00533 0.00026 0.00232 49 | mid_i 1000000 10 0.00684 0.00073 0.00383 50 | neg_i 1000000 10 0.00653 0.00025 0.00353 51 | abs_i 1000000 10 0.01482 0.00022 0.01181 52 | *test*: add_ii 1000000 10 0.00932 0.00051 0.00932 53 | add_ii 1000000 10 0.02357 0.00105 0.01425 54 | add_id 1000000 10 0.02284 0.00256 0.01352 55 | add_di 1000000 10 0.02218 0.00201 0.01286 56 | *test*: sub_ii 1000000 10 0.00883 0.00029 0.00883 57 | sub_ii 1000000 10 0.02273 0.00010 0.01390 58 | sub_id 1000000 10 0.02109 0.00032 0.01226 59 | sub_di 1000000 10 0.02095 0.00039 0.01211 60 | *test*: mul_ii 1000000 10 0.00873 0.00006 0.00873 61 | mul_ii 1000000 10 0.03855 0.00045 0.02982 62 | mul_id 1000000 10 0.02885 0.00028 0.02012 63 | mul_di 1000000 10 0.03025 0.00233 0.02152 64 | *test*: div_ii 1000000 10 0.00910 0.00069 0.00910 65 | div_ii 1000000 10 0.02710 0.00051 0.01800 66 | div_id 1000000 10 0.02894 0.00032 0.01984 67 | div_di 1000000 10 0.02614 0.00133 0.01704 68 | *test*: inv_i 1000000 10 0.00663 0.00021 0.00663 69 | inv_i 1000000 10 0.01981 0.00018 0.01319 70 | *test*: sqr_i 1000000 10 0.00662 0.00026 0.00662 71 | sqr_i 1000000 10 0.02328 0.00093 0.01665 72 | *test*: sqrt_i 1000000 10 0.01388 0.00025 0.01388 73 | sqrt_i 1000000 10 0.02185 0.00072 0.00798 74 | *test*: exp_i 1000000 10 0.02320 0.00079 0.02320 75 | exp_i 1000000 10 0.03509 0.00053 0.01189 76 | *test*: log_i 1000000 10 0.02075 0.00020 0.02075 77 | log_i 1000000 10 0.03272 0.00037 0.01197 78 | *test*: atan_i 1000000 10 0.03768 0.00038 0.03768 79 | atan_i 1000000 10 0.05569 0.00050 0.01801 80 | *test*: x^2 1000000 10 0.06771 0.00065 0.06771 81 | pown_i(2) 1000000 10 0.02412 0.00034 -0.04359 82 | *test*: x^3 1000000 10 0.06726 0.00055 0.06726 83 | pown_i(3) 1000000 10 0.04720 0.00088 -0.02006 84 | *test*: x^(-2) 1000000 10 0.06792 0.00060 0.06792 85 | pown_i(-2) 1000000 10 0.04373 0.00062 -0.02419 86 | *test*: x^(-3) 1000000 10 0.06752 0.00046 0.06752 87 | pown_i(-3) 1000000 10 0.04030 0.00043 -0.02722 88 | -------------------------------------------------------------------------------- /interval1.mli: -------------------------------------------------------------------------------- 1 | (* ========================================================================== *) 2 | (* A simple OCaml interval library *) 3 | (* https://github.com/monadius/ocaml_simple_interval *) 4 | (* *) 5 | (* Author: Alexey Solovyev *) 6 | (* https://github.com/monadius *) 7 | (* *) 8 | (* This file is distributed under the terms of the MIT license *) 9 | (* ========================================================================== *) 10 | 11 | (** A simple OCaml interval library. 12 | 13 | This interval library does not depend on any external files and libraries. 14 | 15 | It is assumed that all floating-point operations are IEEE 754 16 | compatible and the rounding mode is to nearest. 17 | 18 | It is also assumed that OCaml functions [exp], [log], [atan] compute results with 19 | less than 1 ulp error. 20 | 21 | Intervals computed with this library may be not the optimal 22 | floating-point intervals. But the error for each endpoint is at 23 | most 1 ulp (2 ulp for some exceptional cases near the subnormal 24 | range) for most functions (the error of [pown_i] can be larger). 25 | *) 26 | 27 | (** The interval type *) 28 | type interval = { 29 | low : float; 30 | high : float; 31 | } 32 | 33 | (** The empty interval *) 34 | val empty_interval : interval 35 | 36 | (** The entire interval representing (-infinity, infinity) *) 37 | val entire_interval : interval 38 | 39 | (** [[0., 0.]] *) 40 | val zero_interval : interval 41 | 42 | (** [[1., 1.]] *) 43 | val one_interval : interval 44 | 45 | (** {6 Interval operations} *) 46 | 47 | (** Creates an interval from given endpoints *) 48 | val make_interval : float -> float -> interval 49 | 50 | (** Tests if an interval is empty *) 51 | val is_empty : interval -> bool 52 | 53 | (** Tests if an interval is the entire interval *) 54 | val is_entire : interval -> bool 55 | 56 | (** Tests if an interval is valid. A valid interval is either empty 57 | or [[a, b]] with [a <= b], [a < infinity], [-infinity < b]. *) 58 | val is_valid : interval -> bool 59 | 60 | (** Computes a midpoint of an interval as [(a + b) / 2]. This function 61 | may return incorrect results when [a + b] overflows or for the entire 62 | interval. *) 63 | val mid_i_fast : interval -> float 64 | 65 | (** Computes a midpoint of an interval. This function returns finite 66 | values for all valid non-empty intervals. *) 67 | val mid_i : interval -> float 68 | 69 | (** Interval negation *) 70 | val neg_i : interval -> interval 71 | 72 | (** Interval absolute value *) 73 | val abs_i : interval -> interval 74 | 75 | (** Interval maximum *) 76 | val max_ii : interval -> interval -> interval 77 | 78 | (** Interval minimum *) 79 | val min_ii : interval -> interval -> interval 80 | 81 | (** Interval addition *) 82 | val add_ii : interval -> interval -> interval 83 | 84 | (** Addition of an interval and a number *) 85 | val add_id : interval -> float -> interval 86 | 87 | (** Addition of a number and an interval *) 88 | val add_di : float -> interval -> interval 89 | 90 | (** Interval subtraction *) 91 | val sub_ii : interval -> interval -> interval 92 | 93 | (** Subtraction of an interval and a number *) 94 | val sub_id : interval -> float -> interval 95 | 96 | (** Subtraction of a number and an interval *) 97 | val sub_di : float -> interval -> interval 98 | 99 | (** Interval multiplication *) 100 | val mul_ii : interval -> interval -> interval 101 | 102 | (** Multiplication of an interval and a number *) 103 | val mul_id : interval -> float -> interval 104 | 105 | (** Multiplication of a number and an interval *) 106 | val mul_di : float -> interval -> interval 107 | 108 | (** Interval division *) 109 | val div_ii : interval -> interval -> interval 110 | 111 | (** Division of an interval by a number *) 112 | val div_id : interval -> float -> interval 113 | 114 | (** Division of a number by an interval *) 115 | val div_di : float -> interval -> interval 116 | 117 | (** Interval reciprocal *) 118 | val inv_i : interval -> interval 119 | 120 | (** Interval square root *) 121 | val sqrt_i : interval -> interval 122 | 123 | (** Interval square *) 124 | val sqr_i : interval -> interval 125 | 126 | (** Interval integer power *) 127 | val pown_i : interval -> int -> interval 128 | 129 | (** Interval exponential function. It is assumed that the standard 130 | function [exp:float->float] has less than 1 ulp error. *) 131 | val exp_i : interval -> interval 132 | 133 | (** Interval natural logarithm. It is assumed that the standard 134 | function [log:float->float] has less than 1 ulp error. *) 135 | val log_i : interval -> interval 136 | 137 | (** Interval arctangent. It is assumed that the standard 138 | function [atan:float->float] has less than 1 ulp error. *) 139 | val atan_i : interval -> interval 140 | 141 | (** Interval sine (not implemented yet) *) 142 | val sin_i : interval -> interval 143 | 144 | (** Interval cosine (not implemented yet) *) 145 | val cos_i : interval -> interval 146 | 147 | (** {6 Floating-point operations with directed rounding} *) 148 | 149 | (** Computes a successor of a floating-point number *) 150 | val fsucc : float -> float 151 | 152 | (** Computes a predecessor of a floating-point number *) 153 | val fpred : float -> float 154 | 155 | (** Returns a lower bound of the sum of two floating-point numbers *) 156 | val fadd_low : float -> float -> float 157 | 158 | (** Returns an upper bound of the sum of two floating-point numbers *) 159 | val fadd_high : float -> float -> float 160 | 161 | (** Returns a lower bound of the difference of two floating-point numbers *) 162 | val fsub_low : float -> float -> float 163 | 164 | (** Returns an upper bound of the difference of two floating-point numbers *) 165 | val fsub_high : float -> float -> float 166 | 167 | (** Returns a lower bound of the product of two floating-point numbers *) 168 | val fmul_low : float -> float -> float 169 | 170 | (** Returns an upper bound of the product of two floating-point numbers *) 171 | val fmul_high : float -> float -> float 172 | 173 | (** Returns a lower bound of the ratio of two floating-point numbers *) 174 | val fdiv_low : float -> float -> float 175 | 176 | (** Returns an upper bound of the ratio of two floating-point numbers *) 177 | val fdiv_high : float -> float -> float 178 | 179 | (** Returns a lower bound of [x^2] *) 180 | val fsqr_low : float -> float 181 | 182 | (** Returns an upper bound of [x^2] *) 183 | val fsqr_high : float -> float 184 | 185 | (** Returns a lower bound of [sqrt x] *) 186 | val fsqrt_low : float -> float 187 | 188 | (** Returns an upper bound of [sqrt x] *) 189 | val fsqrt_high : float -> float 190 | 191 | (** Returns a lower bound of [exp x] *) 192 | val fexp_low : float -> float 193 | 194 | (** Returns an upper bound of [exp x] *) 195 | val fexp_high : float -> float 196 | 197 | (** Returns a lower bound of [log x] *) 198 | val flog_low : float -> float 199 | 200 | (** Returns an upper bound of [log x] *) 201 | val flog_high : float -> float 202 | 203 | (** Returns a lower bound of [atan x] *) 204 | val fatan_low : float -> float 205 | 206 | (** Returns an upper bound of [atan x] *) 207 | val fatan_high : float -> float 208 | 209 | (** Return a lower bound of [cos x] *) 210 | val fcos_low : float -> float 211 | 212 | (** Returns an upper bound of [cos x] *) 213 | val fcos_high : float -> float 214 | 215 | (** Returns a lower bound of [sin x] *) 216 | val fsin_low : float -> float 217 | 218 | (** Returns an upper bound of [sin x] *) 219 | val fsin_high : float -> float 220 | 221 | (** Returns a lower bound of [x^n] *) 222 | val fpown_low : float -> int -> float 223 | 224 | (** Returns an upper bound of [x^n] *) 225 | val fpown_high : float -> int -> float 226 | -------------------------------------------------------------------------------- /interval2.mli: -------------------------------------------------------------------------------- 1 | (* ========================================================================== *) 2 | (* A simple OCaml interval library *) 3 | (* https://github.com/monadius/ocaml_simple_interval *) 4 | (* *) 5 | (* Author: Alexey Solovyev *) 6 | (* https://github.com/monadius *) 7 | (* *) 8 | (* This file is distributed under the terms of the MIT license *) 9 | (* ========================================================================== *) 10 | 11 | (** A simple OCaml interval library. 12 | 13 | This interval library needs the OCaml [Num] module. 14 | 15 | It is assumed that all floating-point operations are IEEE 754 16 | compatible and the rounding mode is to nearest. 17 | 18 | It is also assumed that OCaml functions [exp], [log], [atan] compute results with 19 | less than 1 ulp error. 20 | 21 | Intervals computed with this library are optimal floating-point 22 | intervals for basic arithmetic operations. 23 | 24 | {!Interval1} provides faster interval functions which are only 25 | slightly less optimal. 26 | *) 27 | 28 | (** The interval type *) 29 | type interval = { 30 | low : float; 31 | high : float; 32 | } 33 | 34 | (** The empty interval *) 35 | val empty_interval : interval 36 | 37 | (** The entire interval representing (-infinity, infinity) *) 38 | val entire_interval : interval 39 | 40 | (** [[0., 0.]] *) 41 | val zero_interval : interval 42 | 43 | (** [[1., 1.]] *) 44 | val one_interval : interval 45 | 46 | (** {6 Interval operations} *) 47 | 48 | (** Creates an interval from given endpoints *) 49 | val make_interval : float -> float -> interval 50 | 51 | (** Tests if an interval is empty *) 52 | val is_empty : interval -> bool 53 | 54 | (** Tests if an interval is the entire interval *) 55 | val is_entire : interval -> bool 56 | 57 | (** Tests if an interval is valid. A valid interval is either empty 58 | or [[a, b]] with [a <= b], [a < infinity], [-infinity < b]. *) 59 | val is_valid : interval -> bool 60 | 61 | (** Computes a midpoint of an interval. This function returns finite 62 | values for all valid non-empty intervals. *) 63 | val mid_i : interval -> float 64 | 65 | (** Interval negation {b (optimal)} *) 66 | val neg_i : interval -> interval 67 | 68 | (** Interval absolute value {b (optimal)} *) 69 | val abs_i : interval -> interval 70 | 71 | (** Interval maximum {b (optimal)} *) 72 | val max_ii : interval -> interval -> interval 73 | 74 | (** Interval minimum {b (optimal)} *) 75 | val min_ii : interval -> interval -> interval 76 | 77 | (** Interval addition {b (optimal)} *) 78 | val add_ii : interval -> interval -> interval 79 | 80 | (** Addition of an interval and a number {b (optimal)} *) 81 | val add_id : interval -> float -> interval 82 | 83 | (** Addition of a number and an interval {b (optimal)} *) 84 | val add_di : float -> interval -> interval 85 | 86 | (** Interval subtraction {b (optimal)} *) 87 | val sub_ii : interval -> interval -> interval 88 | 89 | (** Subtraction of an interval and a number {b (optimal)} *) 90 | val sub_id : interval -> float -> interval 91 | 92 | (** Subtraction of a number and an interval {b (optimal)} *) 93 | val sub_di : float -> interval -> interval 94 | 95 | (** Interval multiplication {b (optimal)} *) 96 | val mul_ii : interval -> interval -> interval 97 | 98 | (** Multiplication of an interval and a number {b (optimal)} *) 99 | val mul_id : interval -> float -> interval 100 | 101 | (** Multiplication of a number and an interval {b (optimal)} *) 102 | val mul_di : float -> interval -> interval 103 | 104 | (** Interval division {b (optimal)} *) 105 | val div_ii : interval -> interval -> interval 106 | 107 | (** Division of an interval by a number {b (optimal)} *) 108 | val div_id : interval -> float -> interval 109 | 110 | (** Division of a number by an interval {b (optimal)} *) 111 | val div_di : float -> interval -> interval 112 | 113 | (** Interval reciprocal {b (optimal)} *) 114 | val inv_i : interval -> interval 115 | 116 | (** Interval square root {b (optimal)} *) 117 | val sqrt_i : interval -> interval 118 | 119 | (** Interval square {b (optimal)} *) 120 | val sqr_i : interval -> interval 121 | 122 | (** Interval integer power. This function returns an optimal interval 123 | but this behavior may change in the future. *) 124 | val pown_i : interval -> int -> interval 125 | 126 | (** Interval exponential function. It is assumed that the standard 127 | function [exp:float->float] has less than 1 ulp error. *) 128 | val exp_i : interval -> interval 129 | 130 | (** Interval natural logarithm. It is assumed that the standard 131 | function [log:float->float] has less than 1 ulp error. *) 132 | val log_i : interval -> interval 133 | 134 | (** Interval arctangent. It is assumed that the standard 135 | function [atan:float->float] has less than 1 ulp error. *) 136 | val atan_i : interval -> interval 137 | 138 | (** Interval sine (not implemented yet) *) 139 | val sin_i : interval -> interval 140 | 141 | (** Interval cosine (not implemented yet) *) 142 | val cos_i : interval -> interval 143 | 144 | (** {6 Floating-point operations with directed rounding} *) 145 | 146 | (** Computes a successor of a floating-point number {b (optimal)} *) 147 | val fsucc : float -> float 148 | 149 | (** Computes a predecessor of a floating-point number {b (optimal)} *) 150 | val fpred : float -> float 151 | 152 | (** Returns a lower bound of the sum of two floating-point numbers {b 153 | (optimal)} *) 154 | val fadd_low : float -> float -> float 155 | 156 | (** Returns an upper bound of the sum of two floating-point numbers {b 157 | (optimal)} *) 158 | val fadd_high : float -> float -> float 159 | 160 | (** Returns a lower bound of the difference of two floating-point 161 | numbers {b (optimal)} *) 162 | val fsub_low : float -> float -> float 163 | 164 | (** Returns an upper bound of the difference of two floating-point 165 | numbers {b (optimal)} *) 166 | val fsub_high : float -> float -> float 167 | 168 | (** Returns a lower bound of the product of two floating-point numbers 169 | {b (optimal)} *) 170 | val fmul_low : float -> float -> float 171 | 172 | (** Returns an upper bound of the product of two floating-point 173 | numbers {b (optimal)} *) 174 | val fmul_high : float -> float -> float 175 | 176 | (** Returns a lower bound of the ratio of two floating-point numbers 177 | {b (optimal)} *) 178 | val fdiv_low : float -> float -> float 179 | 180 | (** Returns an upper bound of the ratio of two floating-point numbers 181 | {b (optimal)} *) 182 | val fdiv_high : float -> float -> float 183 | 184 | (** Returns a lower bound of [x^2] {b (optimal)} *) 185 | val fsqr_low : float -> float 186 | 187 | (** Returns an upper bound of [x^2] {b (optimal)} *) 188 | val fsqr_high : float -> float 189 | 190 | (** Returns a lower bound of [sqrt x] {b (optimal)} *) 191 | val fsqrt_low : float -> float 192 | 193 | (** Returns an upper bound of [sqrt x] {b (optimal)} *) 194 | val fsqrt_high : float -> float 195 | 196 | (** Returns a lower bound of [exp x] *) 197 | val fexp_low : float -> float 198 | 199 | (** Returns an upper bound of [exp x] *) 200 | val fexp_high : float -> float 201 | 202 | (** Returns a lower bound of [log x] *) 203 | val flog_low : float -> float 204 | 205 | (** Returns an upper bound of [log x] *) 206 | val flog_high : float -> float 207 | 208 | (** Returns a lower bound of [atan x] *) 209 | val fatan_low : float -> float 210 | 211 | (** Returns an upper bound of [atan x] *) 212 | val fatan_high : float -> float 213 | 214 | (* 215 | (** Return a lower bound of [cos x] *) 216 | val fcos_low : float -> float 217 | 218 | (** Returns an upper bound of [cos x] *) 219 | val fcos_high : float -> float 220 | 221 | (** Returns a lower bound of [sin x] *) 222 | val fsin_low : float -> float 223 | 224 | (** Returns an upper bound of [sin x] *) 225 | val fsin_high : float -> float 226 | *) 227 | 228 | (** Returns a lower bound of [x^n] *) 229 | val fpown_low : float -> int -> float 230 | 231 | (** Returns an upper bound of [x^n] *) 232 | val fpown_high : float -> int -> float 233 | -------------------------------------------------------------------------------- /tests/p_interval2.ml: -------------------------------------------------------------------------------- 1 | open Test 2 | open Interval2 3 | 4 | let samples = 10000 5 | let repeats = 10 6 | 7 | let uncurry f (a, b) = f a b 8 | 9 | let uncurry_and_swap f (a, b) = f b a 10 | 11 | let interval_of_pair (a, b) = 12 | if is_nan a || is_nan b || (a = infinity && b = neg_infinity) 13 | || (a = infinity && b = infinity) || (a = neg_infinity && b = neg_infinity) then 14 | empty_interval 15 | else if a <= b then 16 | make_interval a b 17 | else 18 | make_interval b a 19 | 20 | let data_f = array_of_stream (performance_data_f ~n:samples ~sign:0) 21 | 22 | let data_f_pos = array_of_stream (performance_data_f ~n:samples ~sign:1) 23 | 24 | let data_f2 = array_of_stream (performance_data_f2 ~n:samples ~sign:0) 25 | 26 | let data_i = Array.map interval_of_pair data_f2 27 | 28 | let data_if = Array.init (Array.length data_i) 29 | (fun i -> data_i.(i), data_f.(i)) 30 | 31 | let data_i_pos = Array.map abs_i data_i 32 | 33 | let data_i2 = 34 | let p (p1, p2) = interval_of_pair p1, interval_of_pair p2 in 35 | let s = performance_data_f2f2 ~n:samples ~sign:0 in 36 | array_of_stream (stream_map p s) 37 | 38 | let run_f ?base_mean name f = 39 | run_performance_test ~repeats ?base_mean ~name f data_f 40 | 41 | let run_f_pos ?base_mean name f = 42 | run_performance_test ~repeats ?base_mean ~name f data_f_pos 43 | 44 | let run_ff ?base_mean name f = 45 | run_performance_test ~repeats ?base_mean ~name (uncurry f) data_f2 46 | 47 | let run_i ?base_mean name f = 48 | run_performance_test ~repeats ?base_mean ~name f data_i 49 | 50 | let run_i_pos ?base_mean name f = 51 | run_performance_test ~repeats ?base_mean ~name f data_i_pos 52 | 53 | let run_if ?base_mean name f = 54 | run_performance_test ~repeats ?base_mean ~name (uncurry f) data_if 55 | 56 | let run_fi ?base_mean name f = 57 | run_performance_test ~repeats ?base_mean ~name (uncurry_and_swap f) data_if 58 | 59 | let run_ii ?base_mean name f = 60 | run_performance_test ~repeats ?base_mean ~name (uncurry f) data_i2 61 | 62 | let test_add_ii {low = a; high = b} {low = c; high = d} = { 63 | low = a +. c; 64 | high = b +. d; 65 | } 66 | 67 | let test_sub_ii {low = a; high = b} {low = c; high = d} = { 68 | low = a -. d; 69 | high = b -. c; 70 | } 71 | 72 | let test_mul_ii {low = a; high = b} {low = c; high = d} = { 73 | low = a *. c; 74 | high = b *. d; 75 | } 76 | 77 | let test_div_ii {low = a; high = b} {low = c; high = d} = { 78 | low = a /. d; 79 | high = b /. c; 80 | } 81 | 82 | let test_inv_i {low = a; high = b} = { 83 | low = 1. /. a; 84 | high = 1. /. b; 85 | } 86 | 87 | let test_sqr_i {low = a; high = b} = { 88 | low = a *. a; 89 | high = b *. b; 90 | } 91 | 92 | let test_sqrt_i {low = a; high = b} = { 93 | low = sqrt a; 94 | high = sqrt b; 95 | } 96 | 97 | let test_exp_i {low = a; high = b} = { 98 | low = exp a; 99 | high = exp b; 100 | } 101 | 102 | let test_log_i {low = a; high = b} = { 103 | low = log a; 104 | high = log b; 105 | } 106 | 107 | let test_atan_i {low = a; high = b} = { 108 | low = atan a; 109 | high = atan b; 110 | } 111 | 112 | let test_pow_i {low = a; high = b} x = { 113 | low = a ** x; 114 | high = b ** x; 115 | } 116 | 117 | (* Tests for floating-point functions *) 118 | let () = 119 | Gc.compact (); 120 | print_performance_header (); 121 | let base_mean, _ = run_f "empty" (fun a -> 0) in 122 | ignore @@ run_ff "empty2" (fun a b -> 0); 123 | ignore @@ run_f "fsucc" ~base_mean fsucc; 124 | ignore @@ run_f "fpred" ~base_mean fpred; 125 | let base_mean, _ = run_ff "+." ( +. ) in 126 | ignore @@ run_ff "fadd_low" ~base_mean fadd_low; 127 | ignore @@ run_ff "fadd_high" ~base_mean fadd_high; 128 | let base_mean, _ = run_ff "-." ( -. ) in 129 | ignore @@ run_ff "fsub_low" ~base_mean fsub_low; 130 | ignore @@ run_ff "fsub_high" ~base_mean fsub_high; 131 | let base_mean, _ = run_ff "*." ( *. ) in 132 | ignore @@ run_ff "fmul_low" ~base_mean fmul_low; 133 | ignore @@ run_ff "fmul_high" ~base_mean fmul_high; 134 | let base_mean, _ = run_ff "/." ( /. ) in 135 | ignore @@ run_ff "fdiv_low" ~base_mean fdiv_low; 136 | ignore @@ run_ff "fdiv_high" ~base_mean fdiv_high; 137 | let base_mean, _ = run_f "sqr" (fun x -> x *. x) in 138 | ignore @@ run_f "fsqr_low" ~base_mean fsqr_low; 139 | ignore @@ run_f "fsqr_high" ~base_mean fsqr_high; 140 | let base_mean, _ = run_f_pos "sqrt" sqrt in 141 | ignore @@ run_f_pos "fsqrt_low" ~base_mean fsqrt_low; 142 | ignore @@ run_f_pos "fsqrt_high" ~base_mean fsqrt_high; 143 | let base_mean, _ = run_f "exp" exp in 144 | ignore @@ run_f "fexp_low" ~base_mean fexp_low; 145 | ignore @@ run_f "fexp_high" ~base_mean fexp_high; 146 | let base_mean, _ = run_f_pos "log" log in 147 | ignore @@ run_f_pos "flog_low" ~base_mean flog_low; 148 | ignore @@ run_f_pos "flog_high" ~base_mean flog_high; 149 | let base_mean, _ = run_f "atan" atan in 150 | ignore @@ run_f "fatan_low" ~base_mean fatan_low; 151 | ignore @@ run_f "fatan_high" ~base_mean fatan_high; 152 | let base_mean, _ = run_f "x^2" (fun x -> x ** 2.) in 153 | ignore @@ run_f "fpown_low(2)" ~base_mean (fun x -> fpown_low x 2); 154 | ignore @@ run_f "fpown_high(2)" ~base_mean (fun x -> fpown_high x 2); 155 | let base_mean, _ = run_f "x^3" (fun x -> x ** 3.) in 156 | ignore @@ run_f "fpown_low(3)" ~base_mean (fun x -> fpown_low x 3); 157 | ignore @@ run_f "fpown_high(3)" ~base_mean (fun x -> fpown_high x 3); 158 | let base_mean, _ = run_f "x^(-2)" (fun x -> x ** (-2.)) in 159 | ignore @@ run_f "fpown_low(-2)" ~base_mean (fun x -> fpown_low x (-2)); 160 | ignore @@ run_f "fpown_high(-2)" ~base_mean (fun x -> fpown_high x (-2)); 161 | let base_mean, _ = run_f "x^(-3)" (fun x -> x ** (-3.)) in 162 | ignore @@ run_f "fpown_low(-3)" ~base_mean (fun x -> fpown_low x (-3)); 163 | ignore @@ run_f "fpown_high(-3)" ~base_mean (fun x -> fpown_high x (-3)) 164 | 165 | 166 | (* Tests for interval functions *) 167 | let () = 168 | Gc.compact (); 169 | Printf.printf "\n"; 170 | print_performance_header (); 171 | let base_mean, _ = run_i "empty" (fun a -> 0) in 172 | ignore @@ run_i "mid_i" ~base_mean mid_i; 173 | ignore @@ run_i "neg_i" ~base_mean neg_i; 174 | ignore @@ run_i "abs_i" ~base_mean abs_i; 175 | let base_mean, _ = run_ii "*test*: add_ii" test_add_ii in 176 | ignore @@ run_ii "add_ii" ~base_mean add_ii; 177 | ignore @@ run_if "add_id" ~base_mean add_id; 178 | ignore @@ run_fi "add_di" ~base_mean add_di; 179 | let base_mean, _ = run_ii "*test*: sub_ii" test_sub_ii in 180 | ignore @@ run_ii "sub_ii" ~base_mean sub_ii; 181 | ignore @@ run_if "sub_id" ~base_mean sub_id; 182 | ignore @@ run_fi "sub_di" ~base_mean sub_di; 183 | let base_mean, _ = run_ii "*test*: mul_ii" test_mul_ii in 184 | ignore @@ run_ii "mul_ii" ~base_mean mul_ii; 185 | ignore @@ run_if "mul_id" ~base_mean mul_id; 186 | ignore @@ run_fi "mul_di" ~base_mean mul_di; 187 | let base_mean, _ = run_ii "*test*: div_ii" test_div_ii in 188 | ignore @@ run_ii "div_ii" ~base_mean div_ii; 189 | ignore @@ run_if "div_id" ~base_mean div_id; 190 | ignore @@ run_fi "div_di" ~base_mean div_di; 191 | let base_mean, _ = run_i "*test*: inv_i" test_inv_i in 192 | ignore @@ run_i "inv_i" ~base_mean inv_i; 193 | let base_mean, _ = run_i "*test*: sqr_i" test_sqr_i in 194 | ignore @@ run_i "sqr_i" ~base_mean sqr_i; 195 | let base_mean, _ = run_i_pos "*test*: sqrt_i" test_sqrt_i in 196 | ignore @@ run_i_pos "sqrt_i" ~base_mean sqrt_i; 197 | let base_mean, _ = run_i "*test*: exp_i" test_exp_i in 198 | ignore @@ run_i "exp_i" ~base_mean exp_i; 199 | let base_mean, _ = run_i_pos "*test*: log_i" test_log_i in 200 | ignore @@ run_i_pos "log_i" ~base_mean log_i; 201 | let base_mean, _ = run_i "*test*: atan_i" test_atan_i in 202 | ignore @@ run_i "atan_i" ~base_mean atan_i; 203 | let base_mean, _ = run_i "*test*: x^2" (fun v -> test_pow_i v 2.) in 204 | ignore @@ run_i "pown_i(2)" ~base_mean (fun v -> pown_i v 2); 205 | let base_mean, _ = run_i "*test*: x^3" (fun v -> test_pow_i v 3.) in 206 | ignore @@ run_i "pown_i(3)" ~base_mean (fun v -> pown_i v 3); 207 | let base_mean, _ = run_i "*test*: x^(-2)" (fun v -> test_pow_i v (-2.)) in 208 | ignore @@ run_i "pown_i(-2)" ~base_mean (fun v -> pown_i v (-2)); 209 | let base_mean, _ = run_i "*test*: x^(-3)" (fun v -> test_pow_i v (-3.)) in 210 | ignore @@ run_i "pown_i(-3)" ~base_mean (fun v -> pown_i v (-3)) 211 | -------------------------------------------------------------------------------- /tests/p_interval1.ml: -------------------------------------------------------------------------------- 1 | open Test 2 | open Interval1 3 | 4 | let samples = 1000000 5 | let repeats = 10 6 | 7 | let uncurry f (a, b) = f a b 8 | 9 | let uncurry_and_swap f (a, b) = f b a 10 | 11 | let interval_of_pair (a, b) = 12 | if is_nan a || is_nan b || (a = infinity && b = neg_infinity) 13 | || (a = infinity && b = infinity) || (a = neg_infinity && b = neg_infinity) then 14 | empty_interval 15 | else if a <= b then 16 | make_interval a b 17 | else 18 | make_interval b a 19 | 20 | let data_f = array_of_stream (performance_data_f ~n:samples ~sign:0) 21 | 22 | let data_f_pos = array_of_stream (performance_data_f ~n:samples ~sign:1) 23 | 24 | let data_f2 = array_of_stream (performance_data_f2 ~n:samples ~sign:0) 25 | 26 | let data_i = Array.map interval_of_pair data_f2 27 | 28 | let data_if = Array.init (Array.length data_i) 29 | (fun i -> data_i.(i), data_f.(i)) 30 | 31 | let data_i_pos = Array.map abs_i data_i 32 | 33 | let data_i2 = 34 | let p (p1, p2) = interval_of_pair p1, interval_of_pair p2 in 35 | let s = performance_data_f2f2 ~n:samples ~sign:0 in 36 | array_of_stream (stream_map p s) 37 | 38 | let run_f ?base_mean name f = 39 | run_performance_test ~repeats ?base_mean ~name f data_f 40 | 41 | let run_f_pos ?base_mean name f = 42 | run_performance_test ~repeats ?base_mean ~name f data_f_pos 43 | 44 | let run_ff ?base_mean name f = 45 | run_performance_test ~repeats ?base_mean ~name (uncurry f) data_f2 46 | 47 | let run_i ?base_mean name f = 48 | run_performance_test ~repeats ?base_mean ~name f data_i 49 | 50 | let run_i_pos ?base_mean name f = 51 | run_performance_test ~repeats ?base_mean ~name f data_i_pos 52 | 53 | let run_if ?base_mean name f = 54 | run_performance_test ~repeats ?base_mean ~name (uncurry f) data_if 55 | 56 | let run_fi ?base_mean name f = 57 | run_performance_test ~repeats ?base_mean ~name (uncurry_and_swap f) data_if 58 | 59 | let run_ii ?base_mean name f = 60 | run_performance_test ~repeats ?base_mean ~name (uncurry f) data_i2 61 | 62 | let test_add_ii {low = a; high = b} {low = c; high = d} = { 63 | low = a +. c; 64 | high = b +. d; 65 | } 66 | 67 | let test_sub_ii {low = a; high = b} {low = c; high = d} = { 68 | low = a -. d; 69 | high = b -. c; 70 | } 71 | 72 | let test_mul_ii {low = a; high = b} {low = c; high = d} = { 73 | low = a *. c; 74 | high = b *. d; 75 | } 76 | 77 | let test_div_ii {low = a; high = b} {low = c; high = d} = { 78 | low = a /. d; 79 | high = b /. c; 80 | } 81 | 82 | let test_inv_i {low = a; high = b} = { 83 | low = 1. /. a; 84 | high = 1. /. b; 85 | } 86 | 87 | let test_sqr_i {low = a; high = b} = { 88 | low = a *. a; 89 | high = b *. b; 90 | } 91 | 92 | let test_sqrt_i {low = a; high = b} = { 93 | low = sqrt a; 94 | high = sqrt b; 95 | } 96 | 97 | let test_exp_i {low = a; high = b} = { 98 | low = exp a; 99 | high = exp b; 100 | } 101 | 102 | let test_log_i {low = a; high = b} = { 103 | low = log a; 104 | high = log b; 105 | } 106 | 107 | let test_atan_i {low = a; high = b} = { 108 | low = atan a; 109 | high = atan b; 110 | } 111 | 112 | let test_pow_i {low = a; high = b} x = { 113 | low = a ** x; 114 | high = b ** x; 115 | } 116 | 117 | (* Tests for floating-point functions *) 118 | let () = 119 | Gc.compact (); 120 | print_performance_header (); 121 | let base_mean, _ = run_f "empty" (fun a -> 0) in 122 | ignore @@ run_ff "empty2" (fun a b -> 0); 123 | ignore @@ run_f "fsucc" ~base_mean fsucc; 124 | ignore @@ run_f "fpred" ~base_mean fpred; 125 | let base_mean, _ = run_ff "+." ( +. ) in 126 | ignore @@ run_ff "fadd_low" ~base_mean fadd_low; 127 | ignore @@ run_ff "fadd_high" ~base_mean fadd_high; 128 | let base_mean, _ = run_ff "-." ( -. ) in 129 | ignore @@ run_ff "fsub_low" ~base_mean fsub_low; 130 | ignore @@ run_ff "fsub_high" ~base_mean fsub_high; 131 | let base_mean, _ = run_ff "*." ( *. ) in 132 | ignore @@ run_ff "fmul_low" ~base_mean fmul_low; 133 | ignore @@ run_ff "fmul_high" ~base_mean fmul_high; 134 | let base_mean, _ = run_ff "/." ( /. ) in 135 | ignore @@ run_ff "fdiv_low" ~base_mean fdiv_low; 136 | ignore @@ run_ff "fdiv_high" ~base_mean fdiv_high; 137 | let base_mean, _ = run_f "sqr" (fun x -> x *. x) in 138 | ignore @@ run_f "fsqr_low" ~base_mean fsqr_low; 139 | ignore @@ run_f "fsqr_high" ~base_mean fsqr_high; 140 | let base_mean, _ = run_f_pos "sqrt" sqrt in 141 | ignore @@ run_f_pos "fsqrt_low" ~base_mean fsqrt_low; 142 | ignore @@ run_f_pos "fsqrt_high" ~base_mean fsqrt_high; 143 | let base_mean, _ = run_f "exp" exp in 144 | ignore @@ run_f "fexp_low" ~base_mean fexp_low; 145 | ignore @@ run_f "fexp_high" ~base_mean fexp_high; 146 | let base_mean, _ = run_f_pos "log" log in 147 | ignore @@ run_f_pos "flog_low" ~base_mean flog_low; 148 | ignore @@ run_f_pos "flog_high" ~base_mean flog_high; 149 | let base_mean, _ = run_f "atan" atan in 150 | ignore @@ run_f "fatan_low" ~base_mean fatan_low; 151 | ignore @@ run_f "fatan_high" ~base_mean fatan_high; 152 | let base_mean, _ = run_f "x^2" (fun x -> x ** 2.) in 153 | ignore @@ run_f "fpown_low(2)" ~base_mean (fun x -> fpown_low x 2); 154 | ignore @@ run_f "fpown_high(2)" ~base_mean (fun x -> fpown_high x 2); 155 | let base_mean, _ = run_f "x^3" (fun x -> x ** 3.) in 156 | ignore @@ run_f "fpown_low(3)" ~base_mean (fun x -> fpown_low x 3); 157 | ignore @@ run_f "fpown_high(3)" ~base_mean (fun x -> fpown_high x 3); 158 | let base_mean, _ = run_f "x^(-2)" (fun x -> x ** (-2.)) in 159 | ignore @@ run_f "fpown_low(-2)" ~base_mean (fun x -> fpown_low x (-2)); 160 | ignore @@ run_f "fpown_high(-2)" ~base_mean (fun x -> fpown_high x (-2)); 161 | let base_mean, _ = run_f "x^(-3)" (fun x -> x ** (-3.)) in 162 | ignore @@ run_f "fpown_low(-3)" ~base_mean (fun x -> fpown_low x (-3)); 163 | ignore @@ run_f "fpown_high(-3)" ~base_mean (fun x -> fpown_high x (-3)) 164 | 165 | 166 | (* Tests for interval functions *) 167 | let () = 168 | Gc.compact (); 169 | Printf.printf "\n"; 170 | print_performance_header (); 171 | let base_mean, _ = run_i "empty" (fun a -> 0) in 172 | ignore @@ run_i "mid_i_fast" ~base_mean mid_i_fast; 173 | ignore @@ run_i "mid_i" ~base_mean mid_i; 174 | ignore @@ run_i "neg_i" ~base_mean neg_i; 175 | ignore @@ run_i "abs_i" ~base_mean abs_i; 176 | let base_mean, _ = run_ii "*test*: add_ii" test_add_ii in 177 | ignore @@ run_ii "add_ii" ~base_mean add_ii; 178 | ignore @@ run_if "add_id" ~base_mean add_id; 179 | ignore @@ run_fi "add_di" ~base_mean add_di; 180 | let base_mean, _ = run_ii "*test*: sub_ii" test_sub_ii in 181 | ignore @@ run_ii "sub_ii" ~base_mean sub_ii; 182 | ignore @@ run_if "sub_id" ~base_mean sub_id; 183 | ignore @@ run_fi "sub_di" ~base_mean sub_di; 184 | let base_mean, _ = run_ii "*test*: mul_ii" test_mul_ii in 185 | ignore @@ run_ii "mul_ii" ~base_mean mul_ii; 186 | ignore @@ run_if "mul_id" ~base_mean mul_id; 187 | ignore @@ run_fi "mul_di" ~base_mean mul_di; 188 | let base_mean, _ = run_ii "*test*: div_ii" test_div_ii in 189 | ignore @@ run_ii "div_ii" ~base_mean div_ii; 190 | ignore @@ run_if "div_id" ~base_mean div_id; 191 | ignore @@ run_fi "div_di" ~base_mean div_di; 192 | let base_mean, _ = run_i "*test*: inv_i" test_inv_i in 193 | ignore @@ run_i "inv_i" ~base_mean inv_i; 194 | let base_mean, _ = run_i "*test*: sqr_i" test_sqr_i in 195 | ignore @@ run_i "sqr_i" ~base_mean sqr_i; 196 | let base_mean, _ = run_i_pos "*test*: sqrt_i" test_sqrt_i in 197 | ignore @@ run_i_pos "sqrt_i" ~base_mean sqrt_i; 198 | let base_mean, _ = run_i "*test*: exp_i" test_exp_i in 199 | ignore @@ run_i "exp_i" ~base_mean exp_i; 200 | let base_mean, _ = run_i_pos "*test*: log_i" test_log_i in 201 | ignore @@ run_i_pos "log_i" ~base_mean log_i; 202 | let base_mean, _ = run_i "*test*: atan_i" test_atan_i in 203 | ignore @@ run_i "atan_i" ~base_mean atan_i; 204 | let base_mean, _ = run_i "*test*: x^2" (fun v -> test_pow_i v 2.) in 205 | ignore @@ run_i "pown_i(2)" ~base_mean (fun v -> pown_i v 2); 206 | let base_mean, _ = run_i "*test*: x^3" (fun v -> test_pow_i v 3.) in 207 | ignore @@ run_i "pown_i(3)" ~base_mean (fun v -> pown_i v 3); 208 | let base_mean, _ = run_i "*test*: x^(-2)" (fun v -> test_pow_i v (-2.)) in 209 | ignore @@ run_i "pown_i(-2)" ~base_mean (fun v -> pown_i v (-2)); 210 | let base_mean, _ = run_i "*test*: x^(-3)" (fun v -> test_pow_i v (-3.)) in 211 | ignore @@ run_i "pown_i(-3)" ~base_mean (fun v -> pown_i v (-3)) 212 | 213 | 214 | -------------------------------------------------------------------------------- /tests/test.ml: -------------------------------------------------------------------------------- 1 | exception Bad_fact of string 2 | 3 | let errors, incr_errors, reset_errors = 4 | let errors = ref 0 in 5 | (fun () -> !errors), 6 | (fun () -> incr errors), 7 | (fun () -> errors := 0) 8 | 9 | (* |> is not defined before 4.01 *) 10 | let (|>) a f = f a 11 | 12 | let fact (str, b) = if not b then raise (Bad_fact str) 13 | 14 | let eta_float = ldexp 1.0 (-1074) 15 | 16 | let is_nan x = (compare x nan = 0) 17 | 18 | let is_finite x = neg_infinity < x && x < infinity && not (is_nan x) 19 | 20 | (* Returns a random floating-point number. 21 | sign: specifies the sign of the result (0 denotes a random sign) 22 | exp: the exponent of the result (does not always hold for very small results) *) 23 | let rand_float sign exp = 24 | let neg_flag = if sign = 0 then Random.bool() else (sign < 0) in 25 | let x = 1.0 +. Random.float (1.0 -. epsilon_float) in 26 | let x = if neg_flag then -.x else x in 27 | ldexp x exp 28 | 29 | (* Auxiliary stream and list functions *) 30 | 31 | let stream_map f stream = 32 | let next i = 33 | try Some (f (Stream.next stream)) 34 | with Stream.Failure -> None in 35 | Stream.from next 36 | 37 | let stream_filter p stream = 38 | let rec next i = 39 | try 40 | let value = Stream.next stream in 41 | if p value then Some value else next i 42 | with Stream.Failure -> None in 43 | Stream.from next 44 | 45 | let stream_concat streams = 46 | let ss = ref streams in 47 | let rec next i = 48 | match !ss with 49 | | [] -> None 50 | | stream :: rest -> 51 | begin 52 | try Some (Stream.next stream) 53 | with Stream.Failure -> (ss := rest; next i) 54 | end in 55 | Stream.from next 56 | 57 | let stream_concat_random streams = 58 | let ss = Array.of_list streams in 59 | let n = ref (Array.length ss) in 60 | let rec next i = 61 | if !n <= 0 then None 62 | else begin 63 | let k = Random.int !n in 64 | try Some (Stream.next ss.(k)) 65 | with Stream.Failure -> 66 | begin 67 | decr n; 68 | ss.(k) <- ss.(!n); 69 | next i 70 | end 71 | end in 72 | Stream.from next 73 | 74 | let all_pairs list = 75 | let rec pairs x s = 76 | match s with 77 | | [] -> [] 78 | | y :: ys -> (x, y) :: pairs x ys in 79 | List.fold_left (fun r x -> List.rev_append (pairs x list) r) [] list 80 | 81 | let stream_pairs stream = 82 | let next i = 83 | try 84 | let x = Stream.next stream in 85 | let y = try Stream.next stream with Stream.Failure -> x in 86 | Some (x, y) 87 | with Stream.Failure -> None in 88 | Stream.from next 89 | 90 | let rev_list_of_stream stream = 91 | let result = ref [] in 92 | Stream.iter (fun x -> result := x :: !result) stream; 93 | !result 94 | 95 | let array_of_stream stream = 96 | rev_list_of_stream stream |> List.rev |> Array.of_list 97 | 98 | (* Streams of floating-point numbers *) 99 | 100 | (* Returns an n-element stream of random floating-point numbers 101 | with exponents in the range [e_min, e_max] *) 102 | let rand_floats ~n ~sign e_min e_max = 103 | assert (e_max >= e_min); 104 | let d = e_max - e_min + 1 in 105 | let next i = 106 | if i >= n then None 107 | else 108 | let e = e_min + Random.int d in 109 | Some (rand_float sign e) in 110 | Stream.from next 111 | 112 | (* Returns a stream of random floating-point numbers 113 | where first n elements have the exponent e_min and the 114 | last n elements have the exponent e_max *) 115 | let rand_floats_all ~n ~sign e_min e_max = 116 | assert (e_max >= e_min); 117 | let e = ref e_min in 118 | let k = ref 0 in 119 | let next i = 120 | if !k >= n then begin 121 | incr e; 122 | k := 0 123 | end; 124 | incr k; 125 | if !e > e_max then None 126 | else Some (rand_float sign !e) in 127 | Stream.from next 128 | 129 | (* Returns a stream of floating-point numbers in the form 130 | +/-2^e with e in [e_min, e_max] *) 131 | let p2_floats ~sign e_min e_max = 132 | assert (e_max >= e_min); 133 | let e = ref e_min in 134 | let next i = 135 | if !e > e_max then None 136 | else begin 137 | let exp = !e in 138 | let m = 139 | if sign > 0 then (incr e; 1.0) 140 | else if sign < 0 then (incr e; -1.0) 141 | else if i land 1 = 0 then 1.0 142 | else (incr e; -1.0) in 143 | Some (ldexp m exp) 144 | end in 145 | Stream.from next 146 | 147 | (* Returns a stream of random floating-point numbers in 148 | the form +/-2^e with e in [e_min, e_max] *) 149 | let rand_p2_floats ~n ~sign e_min e_max = 150 | assert (e_max >= e_min); 151 | let d = e_max - e_min + 1 in 152 | let next i = 153 | if i >= n then None 154 | else begin 155 | let neg_flag = if sign = 0 then Random.bool() else (sign < 0) in 156 | let e = e_min + Random.int d in 157 | let x = ldexp 1.0 e in 158 | if neg_flag then Some (-.x) else Some x 159 | end in 160 | Stream.from next 161 | 162 | 163 | (* Functions for running tests *) 164 | 165 | type 'a test = { 166 | test_name: string; 167 | test_arg_name: 'a -> string; 168 | test_func: 'a -> bool; 169 | } 170 | 171 | let mk_test name arg_name f = { 172 | test_name = name; 173 | test_arg_name = arg_name; 174 | test_func = f 175 | } 176 | 177 | let run_test (test: 'a test) (data: 'a Stream.t) = 178 | let new_line_flag = ref true in 179 | let run x = 180 | try 181 | let result = test.test_func x in 182 | assert result 183 | with 184 | | Bad_fact str -> 185 | incr_errors (); 186 | let msg = Printf.sprintf "\rFAIL (%s): %s" 187 | str (test.test_arg_name x) in 188 | let fmt = Format.err_formatter in 189 | if !new_line_flag then (Format.pp_print_newline fmt (); new_line_flag := false); 190 | Format.pp_print_string fmt msg; 191 | Format.pp_print_newline fmt () 192 | | _ -> 193 | incr_errors (); 194 | let msg = Printf.sprintf "\rFAIL: %s" (test.test_arg_name x) in 195 | let fmt = Format.err_formatter in 196 | if !new_line_flag then (Format.pp_print_newline fmt (); new_line_flag := false); 197 | Format.pp_print_string fmt msg; 198 | Format.pp_print_newline fmt () in 199 | begin 200 | let fmt = Format.std_formatter in 201 | Format.pp_print_string fmt ("Running: " ^ test.test_name ^ " ..."); 202 | Format.pp_print_flush fmt (); 203 | Stream.iter run data; 204 | Format.pp_print_string fmt " done"; 205 | Format.pp_print_newline fmt () 206 | end 207 | 208 | let print_performance_header () = 209 | Printf.printf "%-15s %12s %5s %12s %12s %12s\n%!" 210 | "benchmark" "samples" "n" "mean" "sigma" "overhead" 211 | 212 | let run_performance_test ?(repeats = 10) ?(base_mean = 0.) 213 | ~name (f: 'a -> 'b) (data: 'a array) = 214 | let run f data = 215 | let n = Array.length data in 216 | for i = 0 to n - 1 do 217 | ignore (f data.(i)) 218 | done in 219 | let rec run_tests (n, mean, m2) f data k = 220 | if k > 0 then begin 221 | let time = 222 | let start = Unix.gettimeofday() in 223 | run f data; 224 | Unix.gettimeofday() -. start in 225 | let delta = time -. mean in 226 | let mean_new = mean +. delta /. (n +. 1.) in 227 | let delta2 = time -. mean_new in 228 | run_tests (n +. 1., mean_new, m2 +. delta *. delta2) f data (k - 1) 229 | end 230 | else (mean, if n < 2. then nan else m2 /. (n -. 1.)) in 231 | let samples = Array.length data in 232 | let mean, var = run_tests (0., 0., 0.) f data repeats in 233 | let sigma = sqrt var in 234 | Printf.printf "%-15s %12d %5d %12.5f %12.5f %12.5f\n%!" 235 | name samples repeats mean sigma (mean -. base_mean); 236 | mean, sigma 237 | 238 | let run_tests (test: 'a test) (data: 'a Stream.t list) = 239 | run_test test (stream_concat data) 240 | 241 | let name_f name x = 242 | Printf.sprintf "%s: %.20e" name x 243 | 244 | let name_f2 name (a, b) = 245 | Printf.sprintf "%s: [%.20e, %.20e]" name a b 246 | 247 | let name_f2f2 name ((a, b), (c, d)) = 248 | Printf.sprintf "%s: [%.20e, %.20e] [%.20e, %.20e]" name a b c d 249 | 250 | let name_f2f name ((a, b), c) = 251 | Printf.sprintf "%s: [%.20e, %.20e] %.20e" name a b c 252 | 253 | let name_ff2 name (a, (b, c)) = 254 | Printf.sprintf "%s: %.20e [%.20e, %.20e]" name a b c 255 | 256 | let test_f name f = mk_test name (name_f name) f 257 | 258 | let test_f2 name f = mk_test name (name_f2 name) f 259 | 260 | let test_f2f2 name f = 261 | mk_test name (name_f2f2 name) (fun (p1, p2) -> f p1 p2) 262 | 263 | let test_f2f name f = 264 | mk_test name (name_f2f name) (fun (p, x) -> f p x) 265 | 266 | let test_ff2 name f = 267 | mk_test name (name_ff2 name) (fun (x, p) -> f x p) 268 | 269 | let mk_eq_test ?(cmp = Pervasives.compare) name name_arg f = 270 | mk_test name 271 | (fun (arg, _) -> name_arg arg) 272 | (fun (arg, result) -> cmp (f arg) result = 0) 273 | 274 | let run_eq_f ?cmp name f data = 275 | let test = mk_eq_test ?cmp name (name_f name) f in 276 | let sd = Stream.of_list data in 277 | run_test test sd 278 | 279 | let run_eq_f2 ?cmp name f data = 280 | let test = mk_eq_test ?cmp name (name_f2 name) f in 281 | let sd = Stream.of_list data in 282 | run_test test sd 283 | 284 | let run_eq_f2f2 ?cmp name f data = 285 | let test = mk_eq_test ?cmp name (name_f2f2 name) (fun (p1, p2) -> f p1 p2) in 286 | let sd = Stream.of_list data in 287 | run_test test (stream_map (fun ((a, b), (c, d), r) -> ((a, b), (c, d)), r) sd) 288 | 289 | let run_eq_f2f ?cmp name f data = 290 | let test = mk_eq_test ?cmp name (name_f2f name) (fun (p, x) -> f p x) in 291 | let sd = Stream.of_list data in 292 | run_test test (stream_map (fun ((a, b), c, r) -> ((a, b), c), r) sd) 293 | 294 | let run_eq_ff2 ?cmp name f data = 295 | let test = mk_eq_test ?cmp name (name_ff2 name) (fun (x, p) -> f x p) in 296 | let sd = Stream.of_list data in 297 | run_test test (stream_map (fun (a, (b, c), r) -> (a, (b, c)), r) sd) 298 | 299 | (* Predefined test data *) 300 | 301 | let special_floats = [ 302 | nan; 303 | neg_infinity; 304 | infinity; 305 | 0.0; 306 | -.0.0; 307 | max_float; 308 | -.max_float; 309 | min_float; 310 | -.min_float; 311 | min_float +. eta_float; 312 | min_float -. eta_float; 313 | -.min_float +. eta_float; 314 | -.min_float -. eta_float; 315 | 1.0; 316 | -.1.0; 317 | 1.0 +. epsilon_float; 318 | -.(1.0 +. epsilon_float); 319 | eta_float; 320 | -.eta_float; 321 | ldexp 1.0 (-1073); 322 | -.(ldexp 1.0 (-1073)); 323 | ] 324 | 325 | let special_data_f () = Stream.of_list special_floats 326 | 327 | let special_data_f2 () = 328 | Stream.of_list (List.filter (fun (a, b) -> not (a > b)) 329 | (all_pairs special_floats)) 330 | 331 | let special_data_f2f2 () = 332 | let pairs = List.filter (fun (a, b) -> not (a > b)) 333 | (all_pairs special_floats) in 334 | Stream.of_list (all_pairs pairs) 335 | 336 | let standard_data_f ~n ~sign = 337 | stream_concat [ 338 | rand_floats_all 10 sign (-1074) 1023; 339 | p2_floats sign (-1075) 1023; 340 | stream_concat_random [ 341 | rand_p2_floats (n / 2) sign (-30) 30; 342 | rand_floats (n / 2) sign (-30) 30; 343 | ]; 344 | rand_floats n sign (-1074) 1023 345 | ] 346 | 347 | let standard_data_f2 ~n ~sign = 348 | stream_pairs (standard_data_f (2 * n) sign) 349 | 350 | let standard_data_f2f2 ~n ~sign = 351 | stream_pairs (standard_data_f2 (2 * n) sign) 352 | 353 | let performance_data_f ~n ~sign = rand_floats n sign (-30) (30) 354 | 355 | let performance_data_f2 ~n ~sign = stream_pairs (performance_data_f (2 * n) sign) 356 | 357 | let performance_data_f2f2 ~n ~sign = stream_pairs (performance_data_f2 (2 * n) sign) 358 | -------------------------------------------------------------------------------- /docs/type_Interval2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Interval2 11 | 12 | 13 | sig
14 |   type interval = { low : float; high : float; }
15 |   val empty_interval : Interval2.interval
16 |   val entire_interval : Interval2.interval
17 |   val zero_interval : Interval2.interval
18 |   val one_interval : Interval2.interval
19 |   val make_interval : float -> float -> Interval2.interval
20 |   val is_empty : Interval2.interval -> bool
21 |   val is_entire : Interval2.interval -> bool
22 |   val is_valid : Interval2.interval -> bool
23 |   val mid_i : Interval2.interval -> float
24 |   val neg_i : Interval2.interval -> Interval2.interval
25 |   val abs_i : Interval2.interval -> Interval2.interval
26 |   val max_ii : Interval2.interval -> Interval2.interval -> Interval2.interval
27 |   val min_ii : Interval2.interval -> Interval2.interval -> Interval2.interval
28 |   val add_ii : Interval2.interval -> Interval2.interval -> Interval2.interval
29 |   val add_id : Interval2.interval -> float -> Interval2.interval
30 |   val add_di : float -> Interval2.interval -> Interval2.interval
31 |   val sub_ii : Interval2.interval -> Interval2.interval -> Interval2.interval
32 |   val sub_id : Interval2.interval -> float -> Interval2.interval
33 |   val sub_di : float -> Interval2.interval -> Interval2.interval
34 |   val mul_ii : Interval2.interval -> Interval2.interval -> Interval2.interval
35 |   val mul_id : Interval2.interval -> float -> Interval2.interval
36 |   val mul_di : float -> Interval2.interval -> Interval2.interval
37 |   val div_ii : Interval2.interval -> Interval2.interval -> Interval2.interval
38 |   val div_id : Interval2.interval -> float -> Interval2.interval
39 |   val div_di : float -> Interval2.interval -> Interval2.interval
40 |   val inv_i : Interval2.interval -> Interval2.interval
41 |   val sqrt_i : Interval2.interval -> Interval2.interval
42 |   val sqr_i : Interval2.interval -> Interval2.interval
43 |   val pown_i : Interval2.interval -> int -> Interval2.interval
44 |   val exp_i : Interval2.interval -> Interval2.interval
45 |   val log_i : Interval2.interval -> Interval2.interval
46 |   val atan_i : Interval2.interval -> Interval2.interval
47 |   val sin_i : Interval2.interval -> Interval2.interval
48 |   val cos_i : Interval2.interval -> Interval2.interval
49 |   val fsucc : float -> float
50 |   val fpred : float -> float
51 |   val fadd_low : float -> float -> float
52 |   val fadd_high : float -> float -> float
53 |   val fsub_low : float -> float -> float
54 |   val fsub_high : float -> float -> float
55 |   val fmul_low : float -> float -> float
56 |   val fmul_high : float -> float -> float
57 |   val fdiv_low : float -> float -> float
58 |   val fdiv_high : float -> float -> float
59 |   val fsqr_low : float -> float
60 |   val fsqr_high : float -> float
61 |   val fsqrt_low : float -> float
62 |   val fsqrt_high : float -> float
63 |   val fexp_low : float -> float
64 |   val fexp_high : float -> float
65 |   val flog_low : float -> float
66 |   val flog_high : float -> float
67 |   val fatan_low : float -> float
68 |   val fatan_high : float -> float
69 |   val fpown_low : float -> int -> float
70 |   val fpown_high : float -> int -> float
71 | end
-------------------------------------------------------------------------------- /docs/type_Interval1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Interval1 11 | 12 | 13 | sig
14 |   type interval = { low : float; high : float; }
15 |   val empty_interval : Interval1.interval
16 |   val entire_interval : Interval1.interval
17 |   val zero_interval : Interval1.interval
18 |   val one_interval : Interval1.interval
19 |   val make_interval : float -> float -> Interval1.interval
20 |   val is_empty : Interval1.interval -> bool
21 |   val is_entire : Interval1.interval -> bool
22 |   val is_valid : Interval1.interval -> bool
23 |   val mid_i_fast : Interval1.interval -> float
24 |   val mid_i : Interval1.interval -> float
25 |   val neg_i : Interval1.interval -> Interval1.interval
26 |   val abs_i : Interval1.interval -> Interval1.interval
27 |   val max_ii : Interval1.interval -> Interval1.interval -> Interval1.interval
28 |   val min_ii : Interval1.interval -> Interval1.interval -> Interval1.interval
29 |   val add_ii : Interval1.interval -> Interval1.interval -> Interval1.interval
30 |   val add_id : Interval1.interval -> float -> Interval1.interval
31 |   val add_di : float -> Interval1.interval -> Interval1.interval
32 |   val sub_ii : Interval1.interval -> Interval1.interval -> Interval1.interval
33 |   val sub_id : Interval1.interval -> float -> Interval1.interval
34 |   val sub_di : float -> Interval1.interval -> Interval1.interval
35 |   val mul_ii : Interval1.interval -> Interval1.interval -> Interval1.interval
36 |   val mul_id : Interval1.interval -> float -> Interval1.interval
37 |   val mul_di : float -> Interval1.interval -> Interval1.interval
38 |   val div_ii : Interval1.interval -> Interval1.interval -> Interval1.interval
39 |   val div_id : Interval1.interval -> float -> Interval1.interval
40 |   val div_di : float -> Interval1.interval -> Interval1.interval
41 |   val inv_i : Interval1.interval -> Interval1.interval
42 |   val sqrt_i : Interval1.interval -> Interval1.interval
43 |   val sqr_i : Interval1.interval -> Interval1.interval
44 |   val pown_i : Interval1.interval -> int -> Interval1.interval
45 |   val exp_i : Interval1.interval -> Interval1.interval
46 |   val log_i : Interval1.interval -> Interval1.interval
47 |   val atan_i : Interval1.interval -> Interval1.interval
48 |   val sin_i : Interval1.interval -> Interval1.interval
49 |   val cos_i : Interval1.interval -> Interval1.interval
50 |   val fsucc : float -> float
51 |   val fpred : float -> float
52 |   val fadd_low : float -> float -> float
53 |   val fadd_high : float -> float -> float
54 |   val fsub_low : float -> float -> float
55 |   val fsub_high : float -> float -> float
56 |   val fmul_low : float -> float -> float
57 |   val fmul_high : float -> float -> float
58 |   val fdiv_low : float -> float -> float
59 |   val fdiv_high : float -> float -> float
60 |   val fsqr_low : float -> float
61 |   val fsqr_high : float -> float
62 |   val fsqrt_low : float -> float
63 |   val fsqrt_high : float -> float
64 |   val fexp_low : float -> float
65 |   val fexp_high : float -> float
66 |   val flog_low : float -> float
67 |   val flog_high : float -> float
68 |   val fatan_low : float -> float
69 |   val fatan_high : float -> float
70 |   val fcos_low : float -> float
71 |   val fcos_high : float -> float
72 |   val fsin_low : float -> float
73 |   val fsin_high : float -> float
74 |   val fpown_low : float -> int -> float
75 |   val fpown_high : float -> int -> float
76 | end
-------------------------------------------------------------------------------- /tests/test_interval.ml: -------------------------------------------------------------------------------- 1 | open Num 2 | 3 | (* Auxiliary functions *) 4 | 5 | let next_float x = 6 | match classify_float x with 7 | | FP_nan -> nan 8 | | FP_infinite -> 9 | if x = infinity then x else nan 10 | | FP_zero -> ldexp 1.0 (-1074) 11 | | _ -> 12 | begin 13 | let bits = Int64.bits_of_float x in 14 | if x < 0.0 then 15 | Int64.float_of_bits (Int64.pred bits) 16 | else 17 | Int64.float_of_bits (Int64.succ bits) 18 | end 19 | 20 | let prev_float x = 21 | match classify_float x with 22 | | FP_nan -> nan 23 | | FP_infinite -> 24 | if x = neg_infinity then x else nan 25 | | FP_zero -> ldexp (-1.0) (-1074) 26 | | _ -> 27 | begin 28 | let bits = Int64.bits_of_float x in 29 | if x < 0.0 then 30 | Int64.float_of_bits (Int64.succ bits) 31 | else 32 | Int64.float_of_bits (Int64.pred bits) 33 | end 34 | 35 | let num_of_float x = 36 | match classify_float x with 37 | | FP_zero -> Int 0 38 | | FP_normal | FP_subnormal -> 39 | begin 40 | let m, e = frexp x in 41 | let t = Int64.of_float (ldexp m 53) in 42 | num_of_big_int (Big_int.big_int_of_int64 t) */ (Int 2 **/ Int (e - 53)) 43 | end 44 | | _ -> 45 | failwith (Printf.sprintf "num_of_float: %e" x) 46 | 47 | (* Returns the integer binary logarithm of big_int *) 48 | (* Returns -1 for non-positive numbers *) 49 | let log2_big_int_simple = 50 | let rec log2 acc k = 51 | if Big_int.sign_big_int k <= 0 then acc 52 | else log2 (acc + 1) (Big_int.shift_right_big_int k 1) in 53 | log2 (-1) 54 | 55 | let log2_big_int = 56 | let p = 32 in 57 | let u = Big_int.power_int_positive_int 2 p in 58 | let rec log2 acc k = 59 | if Big_int.ge_big_int k u then 60 | log2 (acc + p) (Big_int.shift_right_big_int k p) 61 | else 62 | acc + log2_big_int_simple k in 63 | log2 0 64 | 65 | (* Returns the integer binary logarithm of the absolute value of num *) 66 | let log2_num r = 67 | let log2 r = log2_big_int (big_int_of_num (floor_num r)) in 68 | let r = abs_num r in 69 | if r = 0); 76 | if sign_num r = 0 then 0.0 77 | else begin 78 | let n = log2_num r in 79 | let k = min (n + 1074) 52 in 80 | if k < 0 then 0.0 81 | else 82 | let m = big_int_of_num (floor_num ((Int 2 **/ Int (k - n)) */ r)) in 83 | let f = Int64.to_float (Big_int.int64_of_big_int m) in 84 | let x = ldexp f (n - k) in 85 | if x = infinity then max_float else x 86 | end 87 | 88 | let float_of_pos_num_hi r = 89 | assert (sign_num r >= 0); 90 | if sign_num r = 0 then 0.0 91 | else begin 92 | let n = log2_num r in 93 | let k = min (n + 1074) 52 in 94 | if k < 0 then ldexp 1.0 (-1074) 95 | else 96 | let t = (Int 2 **/ Int (k - n)) */ r in 97 | let m0 = floor_num t in 98 | let m = if t =/ m0 then big_int_of_num m0 99 | else Big_int.succ_big_int (big_int_of_num m0) in 100 | let f = Int64.to_float (Big_int.int64_of_big_int m) in 101 | ldexp f (n - k) 102 | end 103 | 104 | let float_of_num_lo r = 105 | if sign_num r < 0 then 106 | -. float_of_pos_num_hi (minus_num r) 107 | else 108 | float_of_pos_num_lo r 109 | 110 | let float_of_num_hi r = 111 | if sign_num r < 0 then 112 | -. float_of_pos_num_lo (minus_num r) 113 | else 114 | float_of_pos_num_hi r 115 | 116 | let rec float_min_nan = function 117 | | [] -> failwith "float_min_nan: empty list" 118 | | [x] -> x 119 | | x :: xs -> if x <> x then nan 120 | else let t = float_min_nan xs in 121 | if t <> t || t < x then t else x 122 | 123 | let rec float_max_nan = function 124 | | [] -> failwith "float_max_nan: empty list" 125 | | [x] -> x 126 | | x :: xs -> if x <> x then nan 127 | else let t = float_max_nan xs in 128 | if t <> t || t > x then t else x 129 | 130 | let rec float_min = function 131 | | [] -> infinity 132 | | x :: xs -> if x = x then min x (float_min xs) 133 | else float_min xs 134 | 135 | let rec float_max = function 136 | | [] -> neg_infinity 137 | | x :: xs -> if x = x then max x (float_max xs) 138 | else float_max xs 139 | 140 | 141 | (* We consider that 0.0 is a real 0 and 0.0 = -0.0. 142 | We consider that infinity represents a finite positive number and 143 | neg_infinity represents a finite negative number. 144 | Under these assumptions we have: 145 | 0.0 * infinity = 0.0, 146 | infinity + infinity = infinity, 147 | infinity + neg_infinity = nan (we don't know the sign of the result), 148 | etc. 149 | *) 150 | 151 | let round_hi z r = 152 | match classify_float z with 153 | | FP_nan -> z 154 | | FP_infinite -> 155 | if z = infinity then z 156 | else -.max_float 157 | | _ -> 158 | let rz = num_of_float z in 159 | if compare_num rz r >= 0 then z 160 | else next_float z 161 | 162 | let round_lo z r = 163 | match classify_float z with 164 | | FP_nan -> z 165 | | FP_infinite -> 166 | if z = neg_infinity then z 167 | else max_float 168 | | _ -> 169 | let rz = num_of_float z in 170 | if compare_num rz r <= 0 then z 171 | else prev_float z 172 | 173 | let fadd_lo x y = 174 | match classify_float x, classify_float y with 175 | | FP_zero, _ -> y 176 | | _, FP_zero -> x 177 | | FP_nan, _ | _, FP_nan -> nan 178 | | FP_infinite, _ | _, FP_infinite -> 179 | let r = x +. y in 180 | assert (r = infinity || r = neg_infinity || r <> r); 181 | r 182 | | _ -> 183 | let r = num_of_float x +/ num_of_float y in 184 | float_of_num_lo r 185 | 186 | let fadd_hi x y = 187 | match classify_float x, classify_float y with 188 | | FP_zero, _ -> y 189 | | _, FP_zero -> x 190 | | FP_nan, _ | _, FP_nan -> nan 191 | | FP_infinite, _ | _, FP_infinite -> 192 | let r = x +. y in 193 | assert (r = infinity || r = neg_infinity || r <> r); 194 | r 195 | | _ -> 196 | let r = num_of_float x +/ num_of_float y in 197 | float_of_num_hi r 198 | 199 | let fsub_lo x y = fadd_lo x (-.y) 200 | 201 | let fsub_hi x y = fadd_hi x (-.y) 202 | 203 | let fmul_lo x y = 204 | match classify_float x, classify_float y with 205 | | FP_nan, _ | _, FP_nan -> nan 206 | | FP_zero, _ | _, FP_zero -> 0.0 207 | | FP_infinite, _ | _, FP_infinite -> 208 | let r = x *. y in 209 | assert (r = infinity || r = neg_infinity); 210 | if r = infinity then max_float 211 | else r 212 | | _ -> 213 | let r = num_of_float x */ num_of_float y in 214 | float_of_num_lo r 215 | 216 | let fmul_hi x y = 217 | match classify_float x, classify_float y with 218 | | FP_nan, _ | _, FP_nan -> nan 219 | | FP_zero, _ | _, FP_zero -> 0.0 220 | | FP_infinite, _ | _, FP_infinite -> 221 | let r = x *. y in 222 | assert (r = infinity || r = neg_infinity); 223 | if r = neg_infinity then -.max_float 224 | else r 225 | | _ -> 226 | let r = num_of_float x */ num_of_float y in 227 | float_of_num_hi r 228 | 229 | let fdiv_lo x y = 230 | match classify_float x, classify_float y with 231 | | _, FP_zero -> nan 232 | | FP_nan, _ | _, FP_nan -> nan 233 | | FP_zero, _ -> 0.0 234 | | FP_infinite, FP_infinite -> nan 235 | | FP_infinite, _ | _, FP_infinite -> 236 | let r = x /. y in 237 | assert (r = infinity || r = neg_infinity || r = 0.); 238 | if r = infinity then max_float 239 | else if r = 0. then 240 | if (x >= 0. && y >= 0.) || (x <= 0. && y <= 0.) then 0. 241 | else -.ldexp 1. (-1074) 242 | else neg_infinity 243 | | _ -> 244 | let r = num_of_float x // num_of_float y in 245 | float_of_num_lo r 246 | 247 | let fdiv_hi x y = 248 | match classify_float x, classify_float y with 249 | | _, FP_zero -> nan 250 | | FP_nan, _ | _, FP_nan -> nan 251 | | FP_zero, _ -> 0.0 252 | | FP_infinite, FP_infinite -> nan 253 | | FP_infinite, _ | _, FP_infinite -> 254 | let r = x /. y in 255 | assert (r = infinity || r = neg_infinity || r = 0.); 256 | if r = neg_infinity then -.max_float 257 | else if r = 0. then 258 | if (x >= 0. && y <= 0.) || (x <= 0. && y >= 0.) then 0. 259 | else ldexp 1. (-1074) 260 | else infinity 261 | | _ -> 262 | let r = num_of_float x // num_of_float y in 263 | float_of_num_hi r 264 | 265 | let fsqrt_lo x = 266 | match classify_float x with 267 | | FP_nan -> nan 268 | | FP_infinite -> 269 | if x = infinity then max_float else sqrt x 270 | | FP_zero -> 0.0 271 | | _ -> 272 | if x < 0.0 then nan 273 | else 274 | let z = sqrt x in 275 | let rx = num_of_float x and 276 | rz = num_of_float z in 277 | if compare_num (rz */ rz) rx > 0 then prev_float z 278 | else z 279 | 280 | let fsqrt_hi x = 281 | match classify_float x with 282 | | FP_nan -> nan 283 | | FP_infinite -> sqrt x 284 | | FP_zero -> 0.0 285 | | _ -> 286 | if x < 0.0 then nan 287 | else 288 | let z = sqrt x in 289 | let rx = num_of_float x and 290 | rz = num_of_float z in 291 | if compare_num (rz */ rz) rx < 0 then next_float z 292 | else z 293 | 294 | (* We assume that x^0 = 1 for any x (nan excluded) *) 295 | let fpown_lo x n = 296 | match classify_float x with 297 | | FP_nan -> nan 298 | | FP_zero -> 299 | if n = 0 then 1.0 300 | else if n < 0 then nan 301 | else 0.0 302 | | FP_infinite -> 303 | if n = 0 then 1.0 304 | else if x = infinity then 305 | if n < 0 then 0.0 else infinity 306 | else if n land 1 = 0 then 0.0 307 | else neg_infinity 308 | | _ -> 309 | let r = num_of_float x **/ Int n in 310 | float_of_num_lo r 311 | 312 | let fpown_hi x n = 313 | match classify_float x with 314 | | FP_nan -> nan 315 | | FP_zero -> 316 | if n = 0 then 1.0 317 | else if n < 0 then nan 318 | else 0.0 319 | | FP_infinite -> 320 | if n = 0 then 1.0 321 | else if x = infinity then infinity 322 | else if n land 1 = 1 then 0.0 323 | else infinity 324 | | _ -> 325 | let r = num_of_float x **/ Int n in 326 | float_of_num_hi r 327 | 328 | (* Interval type and functions *) 329 | 330 | (* [0, +infinity] contains all finite positive numbers, etc. *) 331 | (* [+infinity, -infinity] represents the only valid empty interval *) 332 | 333 | type ti = { 334 | lo : float; 335 | hi : float 336 | } 337 | 338 | let empty_interval = {lo = infinity; hi = neg_infinity} 339 | 340 | let entire_interval = {lo = neg_infinity; hi = infinity} 341 | 342 | let zero_interval = {lo = 0.0; hi = 0.0} 343 | 344 | let one_interval = {lo = 1.0; hi = 1.0} 345 | 346 | let is_empty {lo; hi} = (lo = infinity && hi = neg_infinity) 347 | 348 | let is_entire {lo; hi} = (lo = neg_infinity && hi = infinity) 349 | 350 | let is_valid ({lo; hi} as v) = 351 | (lo <= hi && lo < infinity && neg_infinity < hi) || is_empty v 352 | 353 | let is_nan_i {lo; hi} = lo <> lo || hi <> hi 354 | 355 | let is_point {lo; hi} = (lo = hi && lo < infinity && neg_infinity < hi) 356 | 357 | let contains {lo; hi} x = lo <= x && x <= hi 358 | 359 | let mk_i a b = {lo = a; hi = b} 360 | 361 | let mk_const_i x = {lo = x; hi = x} 362 | 363 | let abs_i ({lo; hi} as v) = 364 | if is_empty v then empty_interval 365 | else 366 | let a = abs_float lo and 367 | b = abs_float hi in 368 | if 0.0 <= lo || hi <= 0.0 then 369 | {lo = float_min_nan [a; b]; hi = float_max_nan [a; b]} 370 | else 371 | {lo = 0.0; hi = float_max_nan [a; b]} 372 | 373 | let max_ii ({lo = a; hi = b} as v) ({lo = c; hi = d} as w) = 374 | if is_empty v || is_empty w then empty_interval 375 | else 376 | {lo = max a c; hi = max b d} 377 | 378 | let min_ii ({lo = a; hi = b} as v) ({lo = c; hi = d} as w) = 379 | if is_empty v || is_empty w then empty_interval 380 | else 381 | {lo = min a c; hi = min b d} 382 | 383 | let neg_i ({lo; hi} as v) = 384 | if is_empty v then empty_interval else {lo = -.hi; hi = -.lo} 385 | 386 | let add_ii ({lo = a; hi = b} as v) ({lo = c; hi = d} as w) = 387 | if is_empty v || is_empty w then empty_interval 388 | else 389 | {lo = fadd_lo a c; hi = fadd_hi b d} 390 | 391 | let sub_ii ({lo = a; hi = b} as v) ({lo = c; hi = d} as w) = 392 | if is_empty v || is_empty w then empty_interval 393 | else 394 | {lo = fsub_lo a d; hi = fsub_hi b c} 395 | 396 | let mul_ii ({lo = a; hi = b} as v) ({lo = c; hi = d} as w) = 397 | if is_empty v || is_empty w then empty_interval 398 | else { 399 | lo = float_min_nan [fmul_lo a c; fmul_lo a d; fmul_lo b c; fmul_lo b d]; 400 | hi = float_max_nan [fmul_hi a c; fmul_hi a d; fmul_hi b c; fmul_hi b d] 401 | } 402 | 403 | let div_ii ({lo = a; hi = b} as v) ({lo = c; hi = d} as w) = 404 | if is_empty v || is_empty w || (c = 0.0 && d = 0.0) then empty_interval 405 | else if contains w 0.0 then begin 406 | if a = 0.0 && b = 0.0 then zero_interval 407 | else if c = 0.0 then { 408 | lo = if a >= 0.0 then fdiv_lo a d else neg_infinity; 409 | hi = if b <= 0.0 then fdiv_hi b d else infinity 410 | } 411 | else if d = 0.0 then { 412 | lo = if b <= 0.0 then fdiv_lo b c else neg_infinity; 413 | hi = if a >= 0.0 then fdiv_hi a c else infinity 414 | } 415 | else entire_interval 416 | end 417 | else { 418 | lo = float_min [fdiv_lo a c; fdiv_lo a d; fdiv_lo b c; fdiv_lo b d]; 419 | hi = float_max [fdiv_hi a c; fdiv_hi a d; fdiv_hi b c; fdiv_hi b d] 420 | } 421 | 422 | let add_di x w = add_ii (mk_const_i x) w 423 | 424 | let add_id v y = add_ii v (mk_const_i y) 425 | 426 | let sub_di x w = sub_ii (mk_const_i x) w 427 | 428 | let sub_id v y = sub_ii v (mk_const_i y) 429 | 430 | let mul_di x w = mul_ii (mk_const_i x) w 431 | 432 | let mul_id v y = mul_ii v (mk_const_i y) 433 | 434 | let div_di x w = div_ii (mk_const_i x) w 435 | 436 | let div_id v y = div_ii v (mk_const_i y) 437 | 438 | let inv_i v = div_ii one_interval v 439 | 440 | let sqrt_i ({lo = a; hi = b} as v) = 441 | if is_empty v || b < 0.0 then empty_interval 442 | else { 443 | lo = if a < 0.0 then 0.0 else fsqrt_lo a; 444 | hi = fsqrt_hi b 445 | } 446 | 447 | let pown_i ({lo = a; hi = b} as v) n = 448 | if is_empty v || (n < 0 && a = 0.0 && b = 0.0) then empty_interval 449 | else 450 | match n with 451 | | 0 -> one_interval 452 | | 1 -> v 453 | | n when n land 1 = 1 -> begin 454 | (* odd n *) 455 | if n > 0 then {lo = fpown_lo a n; hi = fpown_hi b n} 456 | else if a >= 0.0 then { 457 | lo = fpown_lo b n; 458 | hi = if a = 0.0 then infinity else fpown_hi a n 459 | } 460 | else if b <= 0.0 then { 461 | lo = if b = 0.0 then neg_infinity else fpown_lo b n; 462 | hi = fpown_hi a n 463 | } 464 | else entire_interval 465 | end 466 | | _ -> begin 467 | (* even n *) 468 | if n > 0 then begin 469 | if a >= 0.0 then {lo = fpown_lo a n; hi = fpown_hi b n} 470 | else if b <= 0.0 then {lo = fpown_lo b n; hi = fpown_hi a n} 471 | else {lo = 0.0; hi = fpown_hi (float_max_nan [abs_float a; abs_float b]) n} 472 | end 473 | else if a >= 0.0 then { 474 | lo = fpown_lo b n; 475 | hi = if a = 0.0 then infinity else fpown_hi a n 476 | } 477 | else if b <= 0.0 then { 478 | lo = fpown_lo a n; 479 | hi = if b = 0.0 then infinity else fpown_hi b n 480 | } 481 | else { 482 | lo = fpown_lo (float_max_nan [abs_float a; abs_float b]) n; 483 | hi = infinity 484 | } 485 | end 486 | 487 | let sqr_i v = pown_i v 2 488 | -------------------------------------------------------------------------------- /interval1.ml: -------------------------------------------------------------------------------- 1 | (* ========================================================================== *) 2 | (* A simple OCaml interval library *) 3 | (* https://github.com/monadius/ocaml_simple_interval *) 4 | (* *) 5 | (* Author: Alexey Solovyev *) 6 | (* https://github.com/monadius *) 7 | (* *) 8 | (* This file is distributed under the terms of the MIT license *) 9 | (* ========================================================================== *) 10 | 11 | let u_float = ldexp 1.0 (-53) 12 | 13 | let eta_float = ldexp 1.0 (-1074) 14 | 15 | let phi_float = u_float *. (1.0 +. 2.0 *. u_float) 16 | 17 | let min_float2 = 2.0 *. min_float 18 | 19 | let _ = assert (min_float = 0.5 *. (1.0 /. u_float) *. eta_float) 20 | let _ = assert (min_float2 = ldexp 1.0 (-1021)) 21 | 22 | (* Make sure that the rounding mode is to nearest even *) 23 | let _ = assert (1.0 < 1.0 +. epsilon_float) 24 | let _ = assert (1.0 +. 0.5 *. epsilon_float = 1.0) 25 | let _ = assert (1.0 +. 0.75 *. epsilon_float = 1.0 +. epsilon_float) 26 | let _ = assert (1.0 -. 0.5 *. epsilon_float < 1.0) 27 | let _ = assert (1.0 -. 0.25 *. epsilon_float = 1.0) 28 | let _ = assert (1.0 -. 0.3 *. epsilon_float = 1.0 -. 0.5 *. epsilon_float) 29 | 30 | (* fsucc and fpred from the [RZBM09] paper (see References in README.md) *) 31 | (* Algorithm 1 *) 32 | 33 | let fsucc x = 34 | let e = phi_float *. abs_float x +. eta_float in 35 | x +. e 36 | 37 | let fpred x = 38 | let e = phi_float *. abs_float x +. eta_float in 39 | x -. e 40 | 41 | let fadd_low x y = 42 | let r = x +. y in 43 | if r = infinity then max_float 44 | else if r = 0. then r 45 | else fpred r 46 | 47 | let fadd_high x y = 48 | let r = x +. y in 49 | if r = neg_infinity then -.max_float 50 | else if r = 0. then r 51 | else fsucc r 52 | 53 | let fsub_low x y = 54 | let r = x -. y in 55 | if r = infinity then max_float 56 | else if r = 0. then r 57 | else fpred r 58 | 59 | let fsub_high x y = 60 | let r = x -. y in 61 | if r = neg_infinity then -.max_float 62 | else if r = 0. then r 63 | else fsucc r 64 | 65 | let fmul_low x y = 66 | if x = 0. || y = 0. then 0. 67 | else 68 | let r = x *. y in 69 | if r = infinity then max_float 70 | else if r = 0. then 71 | if (x >= 0. && y >= 0.) || (x <= 0. && y <= 0.) then 0. 72 | else -.eta_float 73 | else 74 | fpred r 75 | 76 | let fmul_high x y = 77 | if x = 0. || y = 0. then 0. 78 | else 79 | let r = x *. y in 80 | if r = neg_infinity then -.max_float 81 | else if r = 0. then 82 | if (x >= 0. && y <= 0.) || (x <= 0. && y >= 0.) then 0. 83 | else eta_float 84 | else 85 | fsucc r 86 | 87 | let fdiv_low x y = 88 | if x = 0. then (if y <> 0. then 0. else nan) 89 | else 90 | let r = x /. y in 91 | if r = infinity then max_float 92 | else if r = 0. then 93 | if (x >= 0. && y >= 0.) || (x <= 0. && y <= 0.) then 0. 94 | else -.eta_float 95 | else 96 | fpred r 97 | 98 | let fdiv_high x y = 99 | if x = 0. then (if y <> 0. then 0. else nan) 100 | else 101 | let r = x /. y in 102 | if r = neg_infinity then -.max_float 103 | else if r = 0. then 104 | if (x >= 0. && y <= 0.) || (x <= 0. && y >= 0.) then 0. 105 | else eta_float 106 | else 107 | fsucc r 108 | 109 | let fsqr_low x = 110 | let r = x *. x in 111 | if r = infinity then max_float 112 | else if r = 0. then 0. 113 | else 114 | fpred r 115 | 116 | let fsqr_high x = 117 | if x = 0. then 0. else fsucc (x *. x) 118 | 119 | let fsqrt_low x = 120 | if x = 0. then 0. 121 | else 122 | let r = sqrt x in 123 | if r = infinity then max_float 124 | else fpred r 125 | 126 | let fsqrt_high x = 127 | if x = 0. then 0. else fsucc (sqrt x) 128 | 129 | let fexp_low x = 130 | let r = exp x in 131 | if r = infinity then max_float 132 | else if r > 0. then fpred r 133 | else 0. 134 | 135 | let fexp_high x = fsucc (exp x) 136 | 137 | let flog_low x = 138 | if x = 1. then 0. 139 | else 140 | let r = log x in 141 | if r = infinity then max_float 142 | else fpred r 143 | 144 | let flog_high x = 145 | if x = 1. then 0. 146 | else 147 | let r = log x in 148 | if r = neg_infinity then -.max_float 149 | else fsucc r 150 | 151 | let fatan_low x = 152 | if x = 0. then 0. 153 | else 154 | fpred (atan x) 155 | 156 | let fatan_high x = 157 | if x = 0. then 0. 158 | else 159 | fsucc (atan x) 160 | 161 | let fcos_low x = 162 | let r = cos x in 163 | if r > -1.0 then 164 | fpred r 165 | else if r <> r then 166 | nan 167 | else 168 | -1.0 169 | 170 | let fcos_high x = 171 | let r = cos x in 172 | if r < 1.0 then 173 | fsucc r 174 | else if r <> r then 175 | nan 176 | else 177 | 1.0 178 | 179 | let fsin_low x = 180 | let r = sin x in 181 | if r > -1.0 then 182 | fpred r 183 | else if r <> r then 184 | nan 185 | else 186 | -1.0 187 | 188 | let fsin_high x = 189 | let r = sin x in 190 | if r < 1.0 then 191 | fsucc r 192 | else if r <> r then 193 | nan 194 | else 195 | 1.0 196 | 197 | let rec fpown_low_pos x n = 198 | assert (x >= 0. && n > 0); 199 | match n with 200 | | 1 -> x 201 | | 2 -> fsqr_low x 202 | | 3 -> fmul_low x (fsqr_low x) 203 | | 4 -> fsqr_low (fsqr_low x) 204 | | _ -> 205 | if x = 0. then x 206 | else if n land 1 = 0 then 207 | let t = fpown_low_pos x (n lsr 1) in 208 | fsqr_low t 209 | else 210 | fmul_low x (fpown_low_pos x (n - 1)) 211 | 212 | let rec fpown_high_pos x n = 213 | assert (x >= 0. && n > 0); 214 | match n with 215 | | 1 -> x 216 | | 2 -> fsqr_high x 217 | | 3 -> fmul_high x (fsqr_high x) 218 | | 4 -> fsqr_high (fsqr_high x) 219 | | _ -> 220 | if x = 0. then x 221 | else if n land 1 = 0 then 222 | let t = fpown_high_pos x (n lsr 1) in 223 | fsqr_high t 224 | else 225 | fmul_high x (fpown_high_pos x (n - 1)) 226 | 227 | let fpown_low x n = 228 | match n with 229 | | 0 -> 1. 230 | | 1 -> x 231 | | 2 -> fsqr_low x 232 | | n when (n land 1 = 0) || x >= 0. -> begin 233 | let a = abs_float x in 234 | if n > 0 then 235 | if a = infinity then max_float 236 | else fpown_low_pos a n 237 | else 238 | if a = infinity then 0. 239 | else if a = 0. then nan 240 | else fdiv_low 1.0 (fpown_high_pos a (-n)) 241 | end 242 | | _ -> begin 243 | let a = -.x in 244 | if n > 0 then 245 | if a = infinity then neg_infinity 246 | else -.fpown_high_pos a n 247 | else 248 | if a = infinity then -.eta_float 249 | else if a = 0. then nan 250 | else -.(fdiv_high 1.0 (fpown_low_pos a (-n))) 251 | end 252 | 253 | let fpown_high x n = 254 | match n with 255 | | 0 -> 1. 256 | | 1 -> x 257 | | 2 -> fsqr_high x 258 | | n when (n land 1 = 0) || x >= 0. -> begin 259 | let a = abs_float x in 260 | if n > 0 then 261 | if a = infinity then infinity 262 | else fpown_high_pos a n 263 | else 264 | if a = infinity then eta_float 265 | else if a = 0. then nan 266 | else fdiv_high 1.0 (fpown_low_pos a (-n)) 267 | end 268 | | _ -> begin 269 | let a = -.x in 270 | if n > 0 then 271 | if a = infinity then -.max_float 272 | else -.fpown_low_pos a n 273 | else 274 | if a = infinity then 0. 275 | else if a = 0. then nan 276 | else -.(fdiv_low 1.0 (fpown_high_pos a (-n))) 277 | end 278 | 279 | (* 280 | Alternative implementation for n >= 4: 281 | let fpown_high x n = 282 | fexp_high (float_of_int n *. flog_high x) 283 | *) 284 | 285 | type interval = { 286 | low : float; 287 | high : float; 288 | } 289 | 290 | let is_empty {low = a; high = b} = (a = infinity && b = neg_infinity) 291 | 292 | let is_entire {low; high} = (low = neg_infinity && high = infinity) 293 | 294 | let is_valid ({low = a; high = b} as v) = 295 | (a <= b && a < infinity && neg_infinity < b) || is_empty v 296 | 297 | let empty_interval = {low = infinity; high = neg_infinity} 298 | 299 | let entire_interval = {low = neg_infinity; high = infinity} 300 | 301 | let zero_interval = {low = 0.; high = 0.} 302 | 303 | let one_interval = {low = 1.; high = 1.} 304 | 305 | let make_interval a b = {low = a; high = b} 306 | 307 | let mid_i_fast {low = a; high = b} = 0.5 *. (a +. b) 308 | 309 | let mid_i {low = a; high = b} = 310 | if a = neg_infinity then 311 | if b = infinity then 0. else -.max_float 312 | else if b = infinity then max_float 313 | else 314 | let m = 0.5 *. (a +. b) in 315 | if m = infinity || m = neg_infinity then 316 | 0.5 *. a +. 0.5 *. b 317 | else m 318 | 319 | let neg_i {low = a; high = b} = { 320 | low = -.b; 321 | high = -.a; 322 | } 323 | 324 | let abs_i ({low = a; high = b} as v) = 325 | (* The first condition handles positive and empty intervals *) 326 | if 0. <= a then v 327 | else if b <= 0. then 328 | {low = -.b; high = -.a} 329 | else 330 | let a = -.a in 331 | {low = 0.; high = if a <= b then b else a} 332 | 333 | let max_ii {low = a; high = b} {low = c; high = d} = 334 | if a = infinity || c = infinity then empty_interval 335 | else { 336 | low = if a <= c then c else a; 337 | high = if b <= d then d else b; 338 | } 339 | 340 | let min_ii {low = a; high = b} {low = c; high = d} = 341 | if a = infinity || c = infinity then empty_interval 342 | else { 343 | low = if a <= c then a else c; 344 | high = if b <= d then b else d; 345 | } 346 | 347 | let add_ii {low = a; high = b} {low = c; high = d} = 348 | if a = infinity || c = infinity then empty_interval 349 | else { 350 | low = fadd_low a c; 351 | high = fadd_high b d; 352 | } 353 | 354 | let add_id {low = a; high = b} c = 355 | if a = infinity then empty_interval 356 | else { 357 | low = fadd_low a c; 358 | high = fadd_high b c; 359 | } 360 | 361 | let add_di c {low = a; high = b} = 362 | if a = infinity then empty_interval 363 | else { 364 | low = fadd_low c a; 365 | high = fadd_high c b; 366 | } 367 | 368 | let sub_ii {low = a; high = b} {low = c; high = d} = 369 | if a = infinity || c = infinity then empty_interval 370 | else { 371 | low = fsub_low a d; 372 | high = fsub_high b c; 373 | } 374 | 375 | let sub_id {low = a; high = b} c = 376 | if a = infinity then empty_interval 377 | else { 378 | low = fsub_low a c; 379 | high = fsub_high b c; 380 | } 381 | 382 | let sub_di c {low = a; high = b} = 383 | if a = infinity then empty_interval 384 | else { 385 | low = fsub_low c b; 386 | high = fsub_high c a; 387 | } 388 | 389 | let mul_ii {low = a; high = b} {low = c; high = d} = 390 | if a = infinity || c = infinity then empty_interval 391 | else if a >= 0.0 then { 392 | low = (if c >= 0.0 then fmul_low a c else fmul_low b c); 393 | high = (if d >= 0.0 then fmul_high b d else fmul_high a d); 394 | } 395 | else if b <= 0.0 then { 396 | low = (if d <= 0.0 then fmul_low b d else fmul_low a d); 397 | high = (if c <= 0.0 then fmul_high a c else fmul_high b c); 398 | } 399 | else if c >= 0.0 then { 400 | low = fmul_low a d; 401 | high = fmul_high b d; 402 | } 403 | else if d <= 0.0 then { 404 | low = fmul_low b c; 405 | high = fmul_high a c; 406 | } 407 | else { 408 | low = (let ad = a *. d and 409 | bc = b *. c in 410 | fpred (if ad <= bc then ad else bc)); 411 | high = (let ac = a *. c and 412 | bd = b *. d in 413 | fsucc (if bd <= ac then ac else bd)); 414 | } 415 | 416 | let mul_id {low = a; high = b} c = 417 | if a = infinity then empty_interval 418 | else if c > 0.0 then { 419 | low = fmul_low a c; 420 | high = fmul_high b c; 421 | } 422 | else if c < 0.0 then { 423 | low = fmul_low b c; 424 | high = fmul_high a c; 425 | } 426 | else if c = 0.0 then { 427 | low = 0.0; 428 | high = 0.0; 429 | } 430 | else { 431 | low = nan; 432 | high = nan; 433 | } 434 | 435 | let mul_di c i = mul_id i c 436 | 437 | let div_ii {low = a; high = b} {low = c; high = d} = 438 | if a = infinity || c = infinity || (c = 0. && d = 0.) then 439 | empty_interval 440 | else if c > 0.0 then { 441 | low = (if a >= 0.0 then fdiv_low a d else fdiv_low a c); 442 | high = (if b <= 0.0 then fdiv_high b d else fdiv_high b c); 443 | } 444 | else if d < 0.0 then { 445 | low = (if b <= 0.0 then fdiv_low b c else fdiv_low b d); 446 | high = (if a >= 0.0 then fdiv_high a c else fdiv_high a d); 447 | } 448 | else if a = 0. && b = 0. then zero_interval 449 | else if c = 0. then { 450 | low = if a >= 0. then fdiv_low a d else neg_infinity; 451 | high = if b <= 0. then fdiv_high b d else infinity; 452 | } 453 | else if d = 0. then { 454 | low = if b <= 0. then fdiv_low b c else neg_infinity; 455 | high = if a >= 0. then fdiv_high a c else infinity; 456 | } 457 | else entire_interval 458 | 459 | let div_id {low = a; high = b} c = 460 | if a = infinity then empty_interval 461 | else if c > 0.0 then { 462 | low = fdiv_low a c; 463 | high = fdiv_high b c; 464 | } 465 | else if c < 0.0 then { 466 | low = fdiv_low b c; 467 | high = fdiv_high a c; 468 | } 469 | else empty_interval 470 | 471 | let div_di a {low = c; high = d} = 472 | if c = infinity then empty_interval 473 | else if c > 0. then begin 474 | if a >= 0. then { 475 | low = fdiv_low a d; 476 | high = fdiv_high a c; 477 | } 478 | else { 479 | low = fdiv_low a c; 480 | high = fdiv_high a d; 481 | } 482 | end 483 | else if d < 0. then begin 484 | if a >= 0. then { 485 | low = fdiv_low a d; 486 | high = fdiv_high a c; 487 | } 488 | else { 489 | low = fdiv_low a c; 490 | high = fdiv_high a d; 491 | } 492 | end 493 | else if c = 0. && d = 0. then empty_interval 494 | else if a = 0. then zero_interval 495 | else if c = 0. then begin 496 | if a >= 0. then { 497 | low = fdiv_low a d; 498 | high = infinity; 499 | } 500 | else { 501 | low = neg_infinity; 502 | high = fdiv_high a d; 503 | } 504 | end 505 | else if d = 0. then begin 506 | if a >= 0. then { 507 | low = neg_infinity; 508 | high = fdiv_high a c; 509 | } 510 | else { 511 | low = fdiv_low a c; 512 | high = infinity; 513 | } 514 | end 515 | else entire_interval 516 | 517 | let inv_i {low = a; high = b} = 518 | if a = infinity then empty_interval 519 | else if 0. < a || b < 0. then { 520 | low = fdiv_low 1. b; 521 | high = fdiv_high 1. a; 522 | } 523 | else if a = 0. then begin 524 | if b = 0. then empty_interval 525 | else { 526 | low = fdiv_low 1. b; 527 | high = infinity; 528 | } 529 | end 530 | else if b = 0. then { 531 | low = neg_infinity; 532 | high = fdiv_high 1. a; 533 | } 534 | else entire_interval 535 | 536 | let sqrt_i {low = a; high = b} = 537 | if b < 0. then empty_interval 538 | else { 539 | low = if a <= 0. then 0. else fsqrt_low a; 540 | high = fsqrt_high b; 541 | } 542 | 543 | let sqr_i {low = a; high = b} = 544 | if a = infinity then empty_interval 545 | else if a >= 0. then 546 | {low = fsqr_low a; high = fsqr_high b} 547 | else if b <= 0. then 548 | {low = fsqr_low b; high = fsqr_high a} 549 | else 550 | let a = -.a in 551 | let t = if a <= b then b else a in (* max (-.a) b *) 552 | {low = 0.; high = fsucc (t *. t)} 553 | 554 | let pown_i ({low = a; high = b} as v) n = 555 | if a = infinity then empty_interval 556 | else 557 | match n with 558 | | 0 -> one_interval 559 | | 1 -> v 560 | | 2 -> sqr_i v 561 | | n when (n land 1 = 1) -> begin 562 | if n > 0 then 563 | {low = fpown_low a n; high = fpown_high b n} 564 | else begin 565 | if a = 0. && b = 0. then empty_interval 566 | else if a >= 0. then { 567 | low = fpown_low b n; 568 | high = if a = 0. then infinity else fpown_high a n; 569 | } 570 | else if b <= 0. then { 571 | low = if b = 0. then neg_infinity else fpown_low b n; 572 | high = fpown_high a n; 573 | } 574 | else entire_interval 575 | end 576 | end 577 | | _ -> begin 578 | if n > 0 then begin 579 | if a >= 0. then 580 | {low = fpown_low a n; high = fpown_high b n} 581 | else if b <= 0. then 582 | {low = fpown_low b n; high = fpown_high a n} 583 | else 584 | let a = -.a in 585 | let t = if a <= b then b else a in (* max (-.a) b *) 586 | {low = 0.; high = fpown_high t n} 587 | end 588 | else begin 589 | if a = 0. && b = 0. then empty_interval 590 | else if a >= 0. then { 591 | low = fpown_low b n; 592 | high = if a = 0. then infinity else fpown_high a n; 593 | } 594 | else if b <= 0. then { 595 | low = fpown_low a n; 596 | high = if b = 0. then infinity else fpown_high b n; 597 | } 598 | else { 599 | low = fpown_low (let a = -.a in if a <= b then b else a) n; 600 | high = infinity; 601 | } 602 | end 603 | end 604 | 605 | let exp_i {low = a; high = b} = 606 | if a = infinity then empty_interval 607 | else { 608 | low = fexp_low a; 609 | high = fexp_high b; 610 | } 611 | 612 | let log_i {low = a; high = b} = 613 | if b < 0. then empty_interval 614 | else { 615 | low = if a <= 0. then neg_infinity else flog_low a; 616 | high = flog_high b; 617 | } 618 | 619 | let atan_i {low = a; high = b} = 620 | if a = infinity then empty_interval 621 | else { 622 | low = fatan_low a; 623 | high = fatan_high b; 624 | } 625 | 626 | let sin_i {low = a; high = b} = 627 | failwith "sin_i: Not implemented" 628 | 629 | let cos_i {low = a; high = b} = 630 | failwith "cos_i: Not implemented" 631 | 632 | -------------------------------------------------------------------------------- /docs/Interval2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Interval2 17 | 18 | 19 | 22 |

Module Interval2

23 | 24 |
module Interval2: sig .. end
25 | A simple OCaml interval library. 26 |

27 | 28 | This interval library needs the OCaml Num module. 29 |

30 | 31 | It is assumed that all floating-point operations are IEEE 754 32 | compatible and the rounding mode is to nearest. 33 |

34 | 35 | It is also assumed that OCaml functions exp, log, atan compute results with 36 | less than 1 ulp error. 37 |

38 | 39 | Intervals computed with this library are optimal floating-point 40 | intervals for basic arithmetic operations. 41 |

42 | 43 | Interval1 provides faster interval functions which are only 44 | slightly less optimal.
45 |

46 |
47 | 48 |
type interval = {
49 | 50 | 52 | 54 | 55 | 56 | 57 | 59 | 61 | 62 |
51 |    53 | low : float;
58 |    60 | high : float;
63 | } 64 | 65 |
66 | The interval type
67 |
68 | 69 | 70 |
val empty_interval : interval
71 | The empty interval
72 |
73 | 74 |
val entire_interval : interval
75 | The entire interval representing (-infinity, infinity)
76 |
77 | 78 |
val zero_interval : interval
79 | [0., 0.]
80 |
81 | 82 |
val one_interval : interval
83 | [1., 1.]
84 |
85 |
86 |
Interval operations

87 | 88 |
val make_interval : float -> float -> interval
89 | Creates an interval from given endpoints
90 |
91 | 92 |
val is_empty : interval -> bool
93 | Tests if an interval is empty
94 |
95 | 96 |
val is_entire : interval -> bool
97 | Tests if an interval is the entire interval
98 |
99 | 100 |
val is_valid : interval -> bool
101 | Tests if an interval is valid. A valid interval is either empty 102 | or [a, b] with a <= b, a < infinity, -infinity < b.
103 |
104 | 105 |
val mid_i : interval -> float
106 | Computes a midpoint of an interval. This function returns finite 107 | values for all valid non-empty intervals.
108 |
109 | 110 |
val neg_i : interval -> interval
111 | Interval negation (optimal)
112 |
113 | 114 |
val abs_i : interval -> interval
115 | Interval absolute value (optimal)
116 |
117 | 118 |
val max_ii : interval -> interval -> interval
119 | Interval maximum (optimal)
120 |
121 | 122 |
val min_ii : interval -> interval -> interval
123 | Interval minimum (optimal)
124 |
125 | 126 |
val add_ii : interval -> interval -> interval
127 | Interval addition (optimal)
128 |
129 | 130 |
val add_id : interval -> float -> interval
131 | Addition of an interval and a number (optimal)
132 |
133 | 134 |
val add_di : float -> interval -> interval
135 | Addition of a number and an interval (optimal)
136 |
137 | 138 |
val sub_ii : interval -> interval -> interval
139 | Interval subtraction (optimal)
140 |
141 | 142 |
val sub_id : interval -> float -> interval
143 | Subtraction of an interval and a number (optimal)
144 |
145 | 146 |
val sub_di : float -> interval -> interval
147 | Subtraction of a number and an interval (optimal)
148 |
149 | 150 |
val mul_ii : interval -> interval -> interval
151 | Interval multiplication (optimal)
152 |
153 | 154 |
val mul_id : interval -> float -> interval
155 | Multiplication of an interval and a number (optimal)
156 |
157 | 158 |
val mul_di : float -> interval -> interval
159 | Multiplication of a number and an interval (optimal)
160 |
161 | 162 |
val div_ii : interval -> interval -> interval
163 | Interval division (optimal)
164 |
165 | 166 |
val div_id : interval -> float -> interval
167 | Division of an interval by a number (optimal)
168 |
169 | 170 |
val div_di : float -> interval -> interval
171 | Division of a number by an interval (optimal)
172 |
173 | 174 |
val inv_i : interval -> interval
175 | Interval reciprocal (optimal)
176 |
177 | 178 |
val sqrt_i : interval -> interval
179 | Interval square root (optimal)
180 |
181 | 182 |
val sqr_i : interval -> interval
183 | Interval square (optimal)
184 |
185 | 186 |
val pown_i : interval -> int -> interval
187 | Interval integer power. This function returns an optimal interval 188 | but this behavior may change in the future.
189 |
190 | 191 |
val exp_i : interval -> interval
192 | Interval exponential function. It is assumed that the standard 193 | function exp:float->float has less than 1 ulp error.
194 |
195 | 196 |
val log_i : interval -> interval
197 | Interval natural logarithm. It is assumed that the standard 198 | function log:float->float has less than 1 ulp error.
199 |
200 | 201 |
val atan_i : interval -> interval
202 | Interval arctangent. It is assumed that the standard 203 | function atan:float->float has less than 1 ulp error.
204 |
205 | 206 |
val sin_i : interval -> interval
207 | Interval sine (not implemented yet)
208 |
209 | 210 |
val cos_i : interval -> interval
211 | Interval cosine (not implemented yet)
212 |
213 |
214 |
Floating-point operations with directed rounding

215 | 216 |
val fsucc : float -> float
217 | Computes a successor of a floating-point number (optimal)
218 |
219 | 220 |
val fpred : float -> float
221 | Computes a predecessor of a floating-point number (optimal)
222 |
223 | 224 |
val fadd_low : float -> float -> float
225 | Returns a lower bound of the sum of two floating-point numbers (optimal)
226 |
227 | 228 |
val fadd_high : float -> float -> float
229 | Returns an upper bound of the sum of two floating-point numbers (optimal)
230 |
231 | 232 |
val fsub_low : float -> float -> float
233 | Returns a lower bound of the difference of two floating-point 234 | numbers (optimal)
235 |
236 | 237 |
val fsub_high : float -> float -> float
238 | Returns an upper bound of the difference of two floating-point 239 | numbers (optimal)
240 |
241 | 242 |
val fmul_low : float -> float -> float
243 | Returns a lower bound of the product of two floating-point numbers 244 | (optimal)
245 |
246 | 247 |
val fmul_high : float -> float -> float
248 | Returns an upper bound of the product of two floating-point 249 | numbers (optimal)
250 |
251 | 252 |
val fdiv_low : float -> float -> float
253 | Returns a lower bound of the ratio of two floating-point numbers 254 | (optimal)
255 |
256 | 257 |
val fdiv_high : float -> float -> float
258 | Returns an upper bound of the ratio of two floating-point numbers 259 | (optimal)
260 |
261 | 262 |
val fsqr_low : float -> float
263 | Returns a lower bound of x^2 (optimal)
264 |
265 | 266 |
val fsqr_high : float -> float
267 | Returns an upper bound of x^2 (optimal)
268 |
269 | 270 |
val fsqrt_low : float -> float
271 | Returns a lower bound of sqrt x (optimal)
272 |
273 | 274 |
val fsqrt_high : float -> float
275 | Returns an upper bound of sqrt x (optimal)
276 |
277 | 278 |
val fexp_low : float -> float
279 | Returns a lower bound of exp x
280 |
281 | 282 |
val fexp_high : float -> float
283 | Returns an upper bound of exp x
284 |
285 | 286 |
val flog_low : float -> float
287 | Returns a lower bound of log x
288 |
289 | 290 |
val flog_high : float -> float
291 | Returns an upper bound of log x
292 |
293 | 294 |
val fatan_low : float -> float
295 | Returns a lower bound of atan x
296 |
297 | 298 |
val fatan_high : float -> float
299 | Returns an upper bound of atan x
300 |
301 | 302 |
val fpown_low : float -> int -> float
303 | Returns a lower bound of x^n
304 |
305 | 306 |
val fpown_high : float -> int -> float
307 | Returns an upper bound of x^n
308 |
309 | -------------------------------------------------------------------------------- /docs/Interval1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Interval1 17 | 18 | 19 | 22 |

Module Interval1

23 | 24 |
module Interval1: sig .. end
25 | A simple OCaml interval library. 26 |

27 | 28 | This interval library does not depend on any external files and libraries. 29 |

30 | 31 | It is assumed that all floating-point operations are IEEE 754 32 | compatible and the rounding mode is to nearest. 33 |

34 | 35 | It is also assumed that OCaml functions exp, log, atan compute results with 36 | less than 1 ulp error. 37 |

38 | 39 | Intervals computed with this library may be not the optimal 40 | floating-point intervals. But the error for each endpoint is at 41 | most 1 ulp (2 ulp for some exceptional cases near the subnormal 42 | range) for most functions (the error of pown_i can be larger).
43 |

44 |
45 | 46 |
type interval = {
47 | 48 | 50 | 52 | 53 | 54 | 55 | 57 | 59 | 60 |
49 |    51 | low : float;
56 |    58 | high : float;
61 | } 62 | 63 |
64 | The interval type
65 |
66 | 67 | 68 |
val empty_interval : interval
69 | The empty interval
70 |
71 | 72 |
val entire_interval : interval
73 | The entire interval representing (-infinity, infinity)
74 |
75 | 76 |
val zero_interval : interval
77 | [0., 0.]
78 |
79 | 80 |
val one_interval : interval
81 | [1., 1.]
82 |
83 |
84 |
Interval operations

85 | 86 |
val make_interval : float -> float -> interval
87 | Creates an interval from given endpoints
88 |
89 | 90 |
val is_empty : interval -> bool
91 | Tests if an interval is empty
92 |
93 | 94 |
val is_entire : interval -> bool
95 | Tests if an interval is the entire interval
96 |
97 | 98 |
val is_valid : interval -> bool
99 | Tests if an interval is valid. A valid interval is either empty 100 | or [a, b] with a <= b, a < infinity, -infinity < b.
101 |
102 | 103 |
val mid_i_fast : interval -> float
104 | Computes a midpoint of an interval as (a + b) / 2. This function 105 | may return incorrect results when a + b overflows or for the entire 106 | interval.
107 |
108 | 109 |
val mid_i : interval -> float
110 | Computes a midpoint of an interval. This function returns finite 111 | values for all valid non-empty intervals.
112 |
113 | 114 |
val neg_i : interval -> interval
115 | Interval negation
116 |
117 | 118 |
val abs_i : interval -> interval
119 | Interval absolute value
120 |
121 | 122 |
val max_ii : interval -> interval -> interval
123 | Interval maximum
124 |
125 | 126 |
val min_ii : interval -> interval -> interval
127 | Interval minimum
128 |
129 | 130 |
val add_ii : interval -> interval -> interval
131 | Interval addition
132 |
133 | 134 |
val add_id : interval -> float -> interval
135 | Addition of an interval and a number
136 |
137 | 138 |
val add_di : float -> interval -> interval
139 | Addition of a number and an interval
140 |
141 | 142 |
val sub_ii : interval -> interval -> interval
143 | Interval subtraction
144 |
145 | 146 |
val sub_id : interval -> float -> interval
147 | Subtraction of an interval and a number
148 |
149 | 150 |
val sub_di : float -> interval -> interval
151 | Subtraction of a number and an interval
152 |
153 | 154 |
val mul_ii : interval -> interval -> interval
155 | Interval multiplication
156 |
157 | 158 |
val mul_id : interval -> float -> interval
159 | Multiplication of an interval and a number
160 |
161 | 162 |
val mul_di : float -> interval -> interval
163 | Multiplication of a number and an interval
164 |
165 | 166 |
val div_ii : interval -> interval -> interval
167 | Interval division
168 |
169 | 170 |
val div_id : interval -> float -> interval
171 | Division of an interval by a number
172 |
173 | 174 |
val div_di : float -> interval -> interval
175 | Division of a number by an interval
176 |
177 | 178 |
val inv_i : interval -> interval
179 | Interval reciprocal
180 |
181 | 182 |
val sqrt_i : interval -> interval
183 | Interval square root
184 |
185 | 186 |
val sqr_i : interval -> interval
187 | Interval square
188 |
189 | 190 |
val pown_i : interval -> int -> interval
191 | Interval integer power
192 |
193 | 194 |
val exp_i : interval -> interval
195 | Interval exponential function. It is assumed that the standard 196 | function exp:float->float has less than 1 ulp error.
197 |
198 | 199 |
val log_i : interval -> interval
200 | Interval natural logarithm. It is assumed that the standard 201 | function log:float->float has less than 1 ulp error.
202 |
203 | 204 |
val atan_i : interval -> interval
205 | Interval arctangent. It is assumed that the standard 206 | function atan:float->float has less than 1 ulp error.
207 |
208 | 209 |
val sin_i : interval -> interval
210 | Interval sine (not implemented yet)
211 |
212 | 213 |
val cos_i : interval -> interval
214 | Interval cosine (not implemented yet)
215 |
216 |
217 |
Floating-point operations with directed rounding

218 | 219 |
val fsucc : float -> float
220 | Computes a successor of a floating-point number
221 |
222 | 223 |
val fpred : float -> float
224 | Computes a predecessor of a floating-point number
225 |
226 | 227 |
val fadd_low : float -> float -> float
228 | Returns a lower bound of the sum of two floating-point numbers
229 |
230 | 231 |
val fadd_high : float -> float -> float
232 | Returns an upper bound of the sum of two floating-point numbers
233 |
234 | 235 |
val fsub_low : float -> float -> float
236 | Returns a lower bound of the difference of two floating-point numbers
237 |
238 | 239 |
val fsub_high : float -> float -> float
240 | Returns an upper bound of the difference of two floating-point numbers
241 |
242 | 243 |
val fmul_low : float -> float -> float
244 | Returns a lower bound of the product of two floating-point numbers
245 |
246 | 247 |
val fmul_high : float -> float -> float
248 | Returns an upper bound of the product of two floating-point numbers
249 |
250 | 251 |
val fdiv_low : float -> float -> float
252 | Returns a lower bound of the ratio of two floating-point numbers
253 |
254 | 255 |
val fdiv_high : float -> float -> float
256 | Returns an upper bound of the ratio of two floating-point numbers
257 |
258 | 259 |
val fsqr_low : float -> float
260 | Returns a lower bound of x^2
261 |
262 | 263 |
val fsqr_high : float -> float
264 | Returns an upper bound of x^2
265 |
266 | 267 |
val fsqrt_low : float -> float
268 | Returns a lower bound of sqrt x
269 |
270 | 271 |
val fsqrt_high : float -> float
272 | Returns an upper bound of sqrt x
273 |
274 | 275 |
val fexp_low : float -> float
276 | Returns a lower bound of exp x
277 |
278 | 279 |
val fexp_high : float -> float
280 | Returns an upper bound of exp x
281 |
282 | 283 |
val flog_low : float -> float
284 | Returns a lower bound of log x
285 |
286 | 287 |
val flog_high : float -> float
288 | Returns an upper bound of log x
289 |
290 | 291 |
val fatan_low : float -> float
292 | Returns a lower bound of atan x
293 |
294 | 295 |
val fatan_high : float -> float
296 | Returns an upper bound of atan x
297 |
298 | 299 |
val fcos_low : float -> float
300 | Return a lower bound of cos x
301 |
302 | 303 |
val fcos_high : float -> float
304 | Returns an upper bound of cos x
305 |
306 | 307 |
val fsin_low : float -> float
308 | Returns a lower bound of sin x
309 |
310 | 311 |
val fsin_high : float -> float
312 | Returns an upper bound of sin x
313 |
314 | 315 |
val fpown_low : float -> int -> float
316 | Returns a lower bound of x^n
317 |
318 | 319 |
val fpown_high : float -> int -> float
320 | Returns an upper bound of x^n
321 |
322 | -------------------------------------------------------------------------------- /interval2.ml: -------------------------------------------------------------------------------- 1 | (* ========================================================================== *) 2 | (* A simple OCaml interval library *) 3 | (* https://github.com/monadius/ocaml_simple_interval *) 4 | (* *) 5 | (* Author: Alexey Solovyev *) 6 | (* https://github.com/monadius *) 7 | (* *) 8 | (* This file is distributed under the terms of the MIT license *) 9 | (* ========================================================================== *) 10 | 11 | open Num 12 | 13 | let u_float = ldexp 1.0 (-53) 14 | 15 | let eta_float = ldexp 1.0 (-1074) 16 | 17 | let phi_float = u_float *. (1.0 +. 2.0 *. u_float) 18 | 19 | let inv_u_float = 1.0 /. u_float 20 | 21 | let bound1_float = 0.5 *. (eta_float /. (u_float *. u_float)) 22 | 23 | let bound2_float = eta_float /. u_float 24 | 25 | let min_float2 = 2.0 *. min_float 26 | 27 | let _ = assert (min_float = 0.5 *. (1.0 /. u_float) *. eta_float) 28 | let _ = assert (min_float2 = ldexp 1.0 (-1021)) 29 | let _ = assert (bound1_float = ldexp 1.0 (-969)) 30 | let _ = assert (bound2_float = ldexp 1.0 (-1021)) 31 | 32 | (* fsucc and fpred from the RZBM09 paper *) 33 | (* Algorithm 2 *) 34 | 35 | let fsucc x = 36 | let c = abs_float x in 37 | if c >= bound1_float then 38 | x +. phi_float *. c 39 | else if c < bound2_float then 40 | x +. eta_float 41 | else 42 | let y = inv_u_float *. x in 43 | let e = phi_float *. abs_float y in 44 | (y +. e) *. u_float 45 | 46 | let fpred x = 47 | let c = abs_float x in 48 | if c >= bound1_float then 49 | x -. phi_float *. c 50 | else if c < bound2_float then 51 | x -. eta_float 52 | else 53 | let y = inv_u_float *. x in 54 | let e = phi_float *. abs_float y in 55 | (y -. e) *. u_float 56 | 57 | let is_finite x = neg_infinity < x && x < infinity 58 | 59 | let num_of_float x = 60 | if x = 0. then Int 0 61 | else if is_finite x then 62 | begin 63 | let m, e = frexp x in 64 | let t = Int64.of_float (ldexp m 53) in 65 | num_of_big_int (Big_int.big_int_of_int64 t) */ (Int 2 **/ Int (e - 53)) 66 | end 67 | else 68 | failwith (Printf.sprintf "num_of_float: %e" x) 69 | 70 | (* Returns the integer binary logarithm of big_int *) 71 | (* Returns -1 for non-positive numbers *) 72 | let log2_big_int_simple = 73 | let rec log2 acc k = 74 | if Big_int.sign_big_int k <= 0 then acc 75 | else log2 (acc + 1) (Big_int.shift_right_big_int k 1) in 76 | log2 (-1) 77 | 78 | let log2_big_int = 79 | let p = 32 in 80 | let u = Big_int.power_int_positive_int 2 p in 81 | let rec log2 acc k = 82 | if Big_int.ge_big_int k u then 83 | log2 (acc + p) (Big_int.shift_right_big_int k p) 84 | else 85 | acc + log2_big_int_simple k in 86 | log2 0 87 | 88 | (* Returns the integer binary logarithm of the absolute value of num *) 89 | let log2_num r = 90 | let log2 r = log2_big_int (big_int_of_num (floor_num r)) in 91 | let r = abs_num r in 92 | if r = 0); 99 | if sign_num r = 0 then 0.0 100 | else begin 101 | let n = log2_num r in 102 | let k = min (n + 1074) 52 in 103 | if k < 0 then 0.0 104 | else 105 | let m = big_int_of_num (floor_num ((Int 2 **/ Int (k - n)) */ r)) in 106 | let f = Int64.to_float (Big_int.int64_of_big_int m) in 107 | let x = ldexp f (n - k) in 108 | if x = infinity then max_float else x 109 | end 110 | 111 | let float_of_pos_num_hi r = 112 | assert (sign_num r >= 0); 113 | if sign_num r = 0 then 0.0 114 | else begin 115 | let n = log2_num r in 116 | let k = min (n + 1074) 52 in 117 | if k < 0 then ldexp 1.0 (-1074) 118 | else 119 | let t = (Int 2 **/ Int (k - n)) */ r in 120 | let m0 = floor_num t in 121 | let m = if t =/ m0 then big_int_of_num m0 122 | else Big_int.succ_big_int (big_int_of_num m0) in 123 | let f = Int64.to_float (Big_int.int64_of_big_int m) in 124 | ldexp f (n - k) 125 | end 126 | 127 | let float_of_num_lo r = 128 | if sign_num r < 0 then 129 | -.float_of_pos_num_hi (minus_num r) 130 | else 131 | float_of_pos_num_lo r 132 | 133 | let float_of_num_hi r = 134 | if sign_num r < 0 then 135 | -.float_of_pos_num_lo (minus_num r) 136 | else 137 | float_of_pos_num_hi r 138 | 139 | let round_hi z r = 140 | if z = neg_infinity then -.max_float 141 | else if z = infinity then z 142 | else 143 | let rz = num_of_float z in 144 | if compare_num rz r >= 0 then z else fsucc z 145 | 146 | let round_lo z r = 147 | if z = infinity then max_float 148 | else if z = neg_infinity then z 149 | else 150 | let rz = num_of_float z in 151 | if compare_num rz r <= 0 then z else fpred z 152 | 153 | (* Correctly rounded fadd_low and fadd_high operations from JInterval *) 154 | 155 | let fadd_low x y = 156 | let z = x +. y in 157 | if z = infinity then max_float 158 | else 159 | if y < z -. x || x < z -. y then fpred z else z 160 | 161 | let fadd_high x y = 162 | let z = x +. y in 163 | if z = neg_infinity then -.max_float 164 | else 165 | if z -. x < y || z -. y < x then fsucc z else z 166 | 167 | let fsub_low x y = fadd_low x (-.y) 168 | 169 | let fsub_high x y = fadd_high x (-.y) 170 | 171 | (* Correctly rounded fmul_low and fmul_high are based on results from 172 | S. Boldo's formal verification of Dekker algorithm *) 173 | 174 | let factor = ldexp 1. 27 +. 1. 175 | let max_product = fpred (ldexp 1. 1021) 176 | let min_product = fsucc (ldexp 1. (-969)) 177 | let max_factor = ldexp 1. 995 178 | 179 | let two_product_err x y xy = 180 | let px = x *. factor in 181 | let qx = x -. px in 182 | let hx = px +. qx in 183 | let tx = x -. hx in 184 | let py = y *. factor in 185 | let qy = y -. py in 186 | let hy = py +. qy in 187 | let ty = y -. hy in 188 | let r2 = hx *. hy -. xy in 189 | let r2 = r2 +. hx *. ty in 190 | let r2 = r2 +. hy *. tx in 191 | r2 +. tx *. ty 192 | 193 | let fmul_low x y = 194 | if x = 0. || y = 0. then 0. 195 | else 196 | let z = x *. y in 197 | let az = abs_float z in 198 | if abs_float x <= max_factor && abs_float y <= max_factor 199 | && min_product <= az && az <= max_product then 200 | begin 201 | let r = two_product_err x y z in 202 | if r >= 0. then z else fpred z 203 | end 204 | else if z = infinity then max_float 205 | else if z = neg_infinity then z 206 | else 207 | let r = num_of_float x */ num_of_float y in 208 | round_lo z r 209 | 210 | let fmul_high x y = 211 | if x = 0. || y = 0. then 0. 212 | else 213 | let z = x *. y in 214 | let az = abs_float z in 215 | if abs_float x <= max_factor && abs_float y <= max_factor 216 | && min_product <= az && az <= max_product then 217 | begin 218 | let r = two_product_err x y z in 219 | if r <= 0. then z else fsucc z 220 | end 221 | else if z = neg_infinity then -.max_float 222 | else if z = infinity then z 223 | else 224 | let r = num_of_float x */ num_of_float y in 225 | round_hi z r 226 | 227 | let fdiv_low_pos x y = 228 | assert (x >= 0. && y > 0.); 229 | let z = x /. y in 230 | if z = infinity then max_float 231 | else if z = 0. then 0. 232 | else 233 | if fmul_high y z <= x then z else fpred z 234 | 235 | let fdiv_high_pos x y = 236 | assert (x >= 0. && y > 0.); 237 | let z = x /. y in 238 | if z = infinity then infinity 239 | else if z = 0. then 240 | if x = 0. then 0. else eta_float 241 | else 242 | if x <= fmul_low y z then z else fsucc z 243 | 244 | let fdiv_low x y = 245 | if x >= 0. then 246 | if y >= 0. then 247 | fdiv_low_pos x y 248 | else 249 | -.fdiv_high_pos x (-.y) 250 | else 251 | if y <= 0. then 252 | fdiv_low_pos (-.x) (-.y) 253 | else 254 | -.fdiv_high_pos (-.x) y 255 | 256 | let fdiv_high x y = 257 | if x >= 0. then 258 | if y >= 0. then 259 | fdiv_high_pos x y 260 | else 261 | -.fdiv_low_pos x (-.y) 262 | else 263 | if y <= 0. then 264 | fdiv_high_pos (-.x) (-.y) 265 | else 266 | -.fdiv_low_pos (-.x) y 267 | 268 | let sqr_product_err x xx = 269 | let px = x *. factor in 270 | let qx = x -. px in 271 | let hx = px +. qx in 272 | let tx = x -. hx in 273 | let r2 = hx *. hx -. xx in 274 | let r2 = r2 +. hx *. tx in 275 | let r2 = r2 +. hx *. tx in 276 | r2 +. tx *. tx 277 | 278 | let fsqr_low x = 279 | let z = x *. x in 280 | if min_product <= z && z <= max_product then 281 | let r = sqr_product_err x z in 282 | if r >= 0. then z else fpred z 283 | else if z = 0. then 0. 284 | else if z = infinity then max_float 285 | else 286 | let t = num_of_float x in 287 | let r = t */ t in 288 | round_lo z r 289 | 290 | let fsqr_high x = 291 | let z = x *. x in 292 | if min_product <= z && z <= max_product then 293 | let r = sqr_product_err x z in 294 | if r <= 0. then z else fsucc z 295 | else if z = 0. then 296 | if x = 0. then 0. else eta_float 297 | else if z = infinity then z 298 | else 299 | let t = num_of_float x in 300 | let r = t */ t in 301 | round_hi z r 302 | 303 | let fsqrt_low x = 304 | if x < 0. then nan 305 | else if x = infinity then max_float 306 | else 307 | let z = sqrt x in 308 | if fsqr_high z <= x then z else fpred z 309 | 310 | let fsqrt_high x = 311 | if x < 0. then nan 312 | else if x = infinity then infinity 313 | else 314 | let z = sqrt x in 315 | if fsqr_low z >= x then z else fsucc z 316 | 317 | (* We assume that x^0 = 1 for any x *) 318 | let fpown_low x n = 319 | match n with 320 | | 0 -> 1. 321 | | 1 -> x 322 | | 2 -> fsqr_low x 323 | | n when x = 0. -> if n < 0 then nan else 0. 324 | | n when is_finite x -> 325 | let r = num_of_float x **/ Int n in 326 | float_of_num_lo r 327 | | _ -> begin 328 | if x = infinity then 329 | if n < 0 then 0. else max_float 330 | else if n land 1 = 0 then 0. 331 | else neg_infinity 332 | end 333 | 334 | let fpown_high x n = 335 | match n with 336 | | 0 -> 1. 337 | | 1 -> x 338 | | 2 -> fsqr_high x 339 | | n when x = 0. -> if n < 0 then nan else 0. 340 | | n when is_finite x -> 341 | let r = num_of_float x **/ Int n in 342 | float_of_num_hi r 343 | | _ -> begin 344 | if x = infinity then infinity 345 | else if n land 1 = 1 then 0.0 346 | else infinity 347 | end 348 | 349 | let fexp_low x = 350 | let r = exp x in 351 | if r = infinity then max_float 352 | else if r > 0. then fpred r 353 | else 0. 354 | 355 | let fexp_high x = fsucc (exp x) 356 | 357 | let flog_low x = 358 | if x = 1. then 0. 359 | else 360 | let r = log x in 361 | if r = infinity then max_float 362 | else fpred r 363 | 364 | let flog_high x = 365 | if x = 1. then 0. 366 | else 367 | let r = log x in 368 | if r = neg_infinity then -.max_float 369 | else fsucc r 370 | 371 | let fatan_low x = 372 | if x = 0. then 0. 373 | else 374 | fpred (atan x) 375 | 376 | let fatan_high x = 377 | if x = 0. then 0. 378 | else 379 | fsucc (atan x) 380 | 381 | (* Interval type and functions *) 382 | 383 | (* [0, +infinity] contains all finite positive numbers, etc. *) 384 | (* [+infinity, -infinity] represents the only valid empty interval *) 385 | 386 | type interval = { 387 | low : float; 388 | high : float 389 | } 390 | 391 | let empty_interval = {low = infinity; high = neg_infinity} 392 | 393 | let entire_interval = {low = neg_infinity; high = infinity} 394 | 395 | let zero_interval = {low = 0.0; high = 0.0} 396 | 397 | let one_interval = {low = 1.0; high = 1.0} 398 | 399 | let is_empty {low; high} = (low = infinity && high = neg_infinity) 400 | 401 | let is_entire {low; high} = (low = neg_infinity && high = infinity) 402 | 403 | let is_valid ({low; high} as v) = 404 | (low <= high && low < infinity && neg_infinity < high) || is_empty v 405 | 406 | let make_interval a b = {low = a; high = b} 407 | 408 | let mid_i {low = a; high = b} = 409 | if a = neg_infinity then 410 | if b = infinity then 0. else -.max_float 411 | else if b = infinity then max_float 412 | else 413 | let m = 0.5 *. (a +. b) in 414 | if m = infinity || m = neg_infinity then 415 | 0.5 *. a +. 0.5 *. b 416 | else m 417 | 418 | let neg_i {low = a; high = b} = { 419 | low = -.b; 420 | high = -.a; 421 | } 422 | 423 | let abs_i ({low = a; high = b} as v) = 424 | if 0. <= a || is_empty v then v 425 | else if b <= 0. then 426 | {low = -.b; high = -.a} 427 | else 428 | {low = 0.; high = max (-.a) b} 429 | 430 | let max_ii ({low = a; high = b} as v) ({low = c; high = d} as w) = 431 | if is_empty v || is_empty w then empty_interval 432 | else { 433 | low = if a <= c then c else a; 434 | high = if b <= d then d else b; 435 | } 436 | 437 | let min_ii ({low = a; high = b} as v) ({low = c; high = d} as w) = 438 | if is_empty v || is_empty w then empty_interval 439 | else { 440 | low = if a <= c then a else c; 441 | high = if b <= d then b else d; 442 | } 443 | 444 | let add_ii ({low = a; high = b} as v) ({low = c; high = d} as w) = 445 | if is_empty v || is_empty w then empty_interval 446 | else { 447 | low = fadd_low a c; 448 | high = fadd_high b d 449 | } 450 | 451 | let add_id ({low = a; high = b} as v) c = 452 | if is_empty v then empty_interval 453 | else { 454 | low = fadd_low a c; 455 | high = fadd_high b c; 456 | } 457 | 458 | let add_di c ({low = a; high = b} as v) = 459 | if is_empty v then empty_interval 460 | else { 461 | low = fadd_low c a; 462 | high = fadd_high c b; 463 | } 464 | 465 | let sub_ii ({low = a; high = b} as v) ({low = c; high = d} as w) = 466 | if is_empty v || is_empty w then empty_interval 467 | else { 468 | low = fsub_low a d; 469 | high = fsub_high b c; 470 | } 471 | 472 | let sub_id ({low = a; high = b} as v) c = 473 | if is_empty v then empty_interval 474 | else { 475 | low = fsub_low a c; 476 | high = fsub_high b c; 477 | } 478 | 479 | let sub_di c ({low = a; high = b} as v) = 480 | if is_empty v then empty_interval 481 | else { 482 | low = fsub_low c b; 483 | high = fsub_high c a; 484 | } 485 | 486 | let mul_ii ({low = a; high = b} as v) ({low = c; high = d} as w) = 487 | if is_empty v || is_empty w then empty_interval 488 | else if a >= 0.0 then { 489 | low = (if c >= 0.0 then fmul_low a c else fmul_low b c); 490 | high = (if d >= 0.0 then fmul_high b d else fmul_high a d); 491 | } 492 | else if b <= 0.0 then { 493 | low = (if d <= 0.0 then fmul_low b d else fmul_low a d); 494 | high = (if c <= 0.0 then fmul_high a c else fmul_high b c); 495 | } 496 | else if c >= 0.0 then { 497 | low = fmul_low a d; 498 | high = fmul_high b d; 499 | } 500 | else if d <= 0.0 then { 501 | low = fmul_low b c; 502 | high = fmul_high a c; 503 | } 504 | else { 505 | low = min (fmul_low a d) (fmul_low b c); 506 | high = max (fmul_high a c) (fmul_high b d); 507 | } 508 | 509 | let mul_id ({low = a; high = b} as v) c = 510 | if is_empty v then empty_interval 511 | else if c > 0.0 then { 512 | low = fmul_low a c; 513 | high = fmul_high b c; 514 | } 515 | else if c < 0.0 then { 516 | low = fmul_low b c; 517 | high = fmul_high a c; 518 | } 519 | else if c = 0.0 then { 520 | low = 0.0; 521 | high = 0.0; 522 | } 523 | else { 524 | low = nan; 525 | high = nan; 526 | } 527 | 528 | let mul_di c i = mul_id i c 529 | 530 | let div_ii ({low = a; high = b} as v) ({low = c; high = d} as w) = 531 | if is_empty v || is_empty w || (c = 0. && d = 0.) then 532 | empty_interval 533 | else if c > 0.0 then { 534 | low = (if a >= 0.0 then fdiv_low a d else fdiv_low a c); 535 | high = (if b <= 0.0 then fdiv_high b d else fdiv_high b c); 536 | } 537 | else if d < 0.0 then { 538 | low = (if b <= 0.0 then fdiv_low b c else fdiv_low b d); 539 | high = (if a >= 0.0 then fdiv_high a c else fdiv_high a d); 540 | } 541 | else if a = 0. && b = 0. then zero_interval 542 | else if c = 0. then { 543 | low = (if a >= 0. then fdiv_low a d else neg_infinity); 544 | high = (if b <= 0. then fdiv_high b d else infinity); 545 | } 546 | else if d = 0. then { 547 | low = (if b <= 0. then fdiv_low b c else neg_infinity); 548 | high = (if a >= 0. then fdiv_high a c else infinity); 549 | } 550 | else entire_interval 551 | 552 | let div_id ({low = a; high = b} as v) c = 553 | if is_empty v then empty_interval 554 | else if c > 0.0 then { 555 | low = fdiv_low a c; 556 | high = fdiv_high b c; 557 | } 558 | else if c < 0.0 then { 559 | low = fdiv_low b c; 560 | high = fdiv_high a c; 561 | } 562 | else empty_interval 563 | 564 | let div_di a w = 565 | if is_finite a then div_ii {low = a; high = a} w 566 | else {low = nan; high = nan} 567 | 568 | let inv_i ({low = a; high = b} as v) = 569 | if is_empty v then empty_interval 570 | else if 0. < a || b < 0. then { 571 | low = fdiv_low 1. b; 572 | high = fdiv_high 1. a; 573 | } 574 | else if a = 0. then begin 575 | if b = 0. then empty_interval 576 | else { 577 | low = fdiv_low 1. b; 578 | high = infinity; 579 | } 580 | end 581 | else if b = 0. then { 582 | low = neg_infinity; 583 | high = fdiv_high 1. a; 584 | } 585 | else entire_interval 586 | 587 | let sqrt_i ({low = a; high = b} as v) = 588 | if b < 0. || is_empty v then empty_interval 589 | else { 590 | low = if a <= 0. then 0. else fsqrt_low a; 591 | high = fsqrt_high b; 592 | } 593 | 594 | let sqr_i ({low = a; high = b} as v) = 595 | if is_empty v then empty_interval 596 | else if a >= 0. then 597 | {low = fsqr_low a; high = fsqr_high b} 598 | else if b <= 0. then 599 | {low = fsqr_low b; high = fsqr_high a} 600 | else 601 | let t = max (-.a) b in 602 | {low = 0.; high = fsqr_high t} 603 | 604 | let pown_i ({low = a; high = b} as v) n = 605 | if is_empty v then empty_interval 606 | else 607 | match n with 608 | | 0 -> one_interval 609 | | 1 -> v 610 | | 2 -> sqr_i v 611 | | -1 -> inv_i v 612 | | n when (n land 1 = 1) -> begin 613 | if n > 0 then 614 | {low = fpown_low a n; high = fpown_high b n} 615 | else begin 616 | if a = 0. && b = 0. then empty_interval 617 | else if a >= 0. then { 618 | low = fpown_low b n; 619 | high = if a = 0. then infinity else fpown_high a n; 620 | } 621 | else if b <= 0. then { 622 | low = if b = 0. then neg_infinity else fpown_low b n; 623 | high = fpown_high a n; 624 | } 625 | else entire_interval 626 | end 627 | end 628 | | _ -> begin 629 | if n > 0 then begin 630 | if a >= 0. then 631 | {low = fpown_low a n; high = fpown_high b n} 632 | else if b <= 0. then 633 | {low = fpown_low b n; high = fpown_high a n} 634 | else 635 | let t = max (-.a) b in 636 | {low = 0.; high = fpown_high t n} 637 | end 638 | else begin 639 | if a = 0. && b = 0. then empty_interval 640 | else if a >= 0. then { 641 | low = fpown_low b n; 642 | high = if a = 0. then infinity else fpown_high a n; 643 | } 644 | else if b <= 0. then { 645 | low = fpown_low a n; 646 | high = if b = 0. then infinity else fpown_high b n; 647 | } 648 | else { 649 | low = fpown_low (max (-.a) b) n; 650 | high = infinity; 651 | } 652 | end 653 | end 654 | 655 | let exp_i ({low = a; high = b} as v) = 656 | if is_empty v then empty_interval 657 | else { 658 | low = fexp_low a; 659 | high = fexp_high b; 660 | } 661 | 662 | let log_i ({low = a; high = b} as v) = 663 | if b < 0. || is_empty v then empty_interval 664 | else { 665 | low = if a <= 0. then neg_infinity else flog_low a; 666 | high = flog_high b; 667 | } 668 | 669 | let atan_i ({low = a; high = b} as v) = 670 | if is_empty v then empty_interval 671 | else { 672 | low = fatan_low a; 673 | high = fatan_high b; 674 | } 675 | 676 | let sin_i {low = a; high = b} = 677 | failwith "sin_i: Not implemented" 678 | 679 | let cos_i {low = a; high = b} = 680 | failwith "cos_i: Not implemented" 681 | --------------------------------------------------------------------------------