diff --git a/.gitignore b/.gitignore index c33c273..4b4a6bc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ target -Cargo.lock -perf.data* \ No newline at end of file +perf.data* diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d8cab5f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,822 @@ +[[package]] +name = "aho-corasick" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cast" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-stats 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools-num 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion-plot" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion-stats" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thread-scoped 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "derive_builder" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "derive_builder_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "derive_builder_core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "env_logger" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fast-math" +version = "0.1.1" +dependencies = [ + "criterion 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "ieee754 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "float-cmp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "handlebars" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "humantime" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ieee754" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "itertools" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools-num" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.45" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "matrixmultiply" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ndarray" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "matrixmultiply 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-complex" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num_cpus" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "optimiser" +version = "0.1.0" +dependencies = [ + "fast-math 0.1.1", + "ieee754 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ndarray 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "optimize 0.1.0 (git+https://github.com/to266/optimize)", +] + +[[package]] +name = "optimize" +version = "0.1.0" +source = "git+https://github.com/to266/optimize#3f7617743134fc26fb6a47a282e42818436dc264" +dependencies = [ + "derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ndarray 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pest_derive" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quickcheck" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rawpointer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ryu" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde" +version = "1.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synom" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread-scoped" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ucd-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "utf8-ranges" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wincolor" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e5f34df7a019573fb8bdc7e24a2bfebe51a2a1d6bfdbaeccedb3c41fc574727" +"checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" +"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" +"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" +"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum criterion 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f8df98670b866802f983ae1aa1bc5ac96d4b71ed0a5f4f550eb8cf0e0e9796ba" +"checksum criterion-plot 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5f81689739e463ece7a6b62c6ec63bdab5c4e28fe05ff451769e87d1511411" +"checksum criterion-stats 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "387df94cb74ada1b33e10ce034bb0d9360cc73edb5063e7d7d4120a40ee1c9d2" +"checksum csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd1c44c58078cfbeaf11fbb3eac9ae5534c23004ed770cc4bfb48e658ae4f04" +"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" +"checksum derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c998e6ab02a828dd9735c18f154e14100e674ed08cb4e1938f0e4177543f439" +"checksum derive_builder_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "735e24ee9e5fa8e16b86da5007856e97d592e11867e45d76e0c0d0a164a0b757" +"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" +"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum handlebars 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3623110a77811256820e92df1b3b286f6f44f99d1f77a94b75e262c28d5034f4" +"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum ieee754 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9007da9cacbd3e6343da136e98b0d2df013f553d35bdec8b518f07bea768e19c" +"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" +"checksum itertools-num 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a872a22f9e6f7521ca557660adb96dd830e54f0f490fa115bb55dd69d38b27e7" +"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" +"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" +"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +"checksum matrixmultiply 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "dcad67dcec2d58ff56f6292582377e6921afdf3bfbd533e26fb8900ae575e002" +"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9" +"checksum ndarray 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d24c5ba54015d7d5203ca6f00d4cc16c71042bf7f7be26f091236f390a16a" +"checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" +"checksum optimize 0.1.0 (git+https://github.com/to266/optimize)" = "" +"checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" +"checksum pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3294f437119209b084c797604295f40227cffa35c57220b1e99a6ff3bf8ee4" +"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4537d3e4edf73a15dd059b75bed1c292d17d3ea7517f583cebe716794fcf816" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" +"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" +"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" +"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" +"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" +"checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019" +"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" +"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" +"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" +"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" +"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" +"checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" +"checksum serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d6115a3ca25c224e409185325afc16a0d5aaaabc15c42b09587d6f1ba39a5b" +"checksum serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "bdf540260cfee6da923831f4776ddc495ada940c30117977c70f1313a6130545" +"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" +"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" +"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" +"checksum thread-scoped 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bcbb6aa301e5d3b0b5ef639c9a9c7e2f1c944f177b460c04dc24c69b1fa2bd99" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" diff --git a/Cargo.toml b/Cargo.toml index b915b0a..4345a53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,9 @@ unstable = [] [[bench]] name = "bench" harness = false + +[workspace] + +members = [ + "optimiser", +] diff --git a/benches/bench.rs b/benches/bench.rs index 2cda35a..f850bba 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -4,6 +4,8 @@ extern crate fast_math; extern crate criterion; use criterion::{Criterion, Fun, black_box}; +use std::f32::consts::{LN_2, LOG2_E}; + fn bench(c: &mut Criterion, name: &str, values: &'static [f32], fast: &'static Fast, raw: &'static Raw, std: &'static Std) where @@ -98,6 +100,18 @@ fn bench_log2(c: &mut Criterion) { ]; bench(c, "log2", values, &fast_math::log2, &fast_math::log2_raw, &f32::log2) } +fn bench_log2_1p(c: &mut Criterion) { + let values = &[ + -0.85708036, 2.43390621, 2.80163358, 2.55126348, 3.18046186, + 2.88689427, 0.32215155, -0.07701401, 1.22922506, -0.4580259 , + 0.01257442, 4.23107197, 0.89538113, 1.65219582, 0.14632742, + 1.68663984, 1.88125115, 2.16773942, 1.27461936, -0.03091265 + ]; + fn log2_1p(x: f32) -> f32 { + x.ln_1p() * LOG2_E + } + bench(c, "log2_1p", values, &fast_math::log2_1p, &fast_math::log2_1p_raw, &log2_1p) +} fn bench_atan(c: &mut Criterion) { let values = &[ @@ -129,6 +143,29 @@ fn bench_exp2(c: &mut Criterion) { bench(c, "exp2", values, &fast_math::exp2, &fast_math::exp2_raw, &f32::exp2) } +fn bench_exp_m1(c: &mut Criterion) { + let values = &[ + 1.0 * 0.85708036, 1.0 * -2.43390621, 1.0 * 2.80163358, 1.0 * -2.55126348, 1.0 * 3.18046186, + 1.0 * -2.88689427, 1.0 * 0.32215155, 1.0 * -0.07701401, 1.0 * 1.22922506, 1.0 * -0.4580259, + 1.0 * 0.01257442, 1.0 * -4.23107197, 1.0 * 0.89538113, 1.0 * -1.65219582, 1.0 * 0.14632742, + 1.0 * -1.68663984, 1.0 * 1.88125115, 1.0 * -2.16773942, 1.0 * 1.27461936, 1.0 * -1.03091265 + ]; + bench(c, "exp_m1", values, &fast_math::exp_m1, &fast_math::exp_m1_raw, &f32::exp_m1) +} + +fn bench_exp2_m1(c: &mut Criterion) { + let values = &[ + 1.0 * 0.85708036, 1.0 * -2.43390621, 1.0 * 2.80163358, 1.0 * -2.55126348, 1.0 * 3.18046186, + 1.0 * -2.88689427, 1.0 * 0.32215155, 1.0 * -0.07701401, 1.0 * 1.22922606, 1.0 * -0.4580259, + 1.0 * 0.01257442, 1.0 * -4.23107197, 1.0 * 0.89538113, 1.0 * -1.65219582, 1.0 * 0.14632742, + 1.0 * -1.68663984, 1.0 * 1.88125115, 1.0 * -2.16773942, 1.0 * 1.27461936, 1.0 * -1.03091265 + ]; + fn exp2_m1(x: f32) -> f32 { + (x * LN_2).exp_m1() + } + bench(c, "exp2_m1", values, &fast_math::exp2_m1, &fast_math::exp2_m1_raw, &exp2_m1) +} + fn bench_atan2(c: &mut Criterion) { let baseline = Fun::new( "baseline", @@ -158,5 +195,7 @@ fn bench_atan2(c: &mut Criterion) { c.bench_functions("scalar/atan2", vec![baseline, full, std], values); } -criterion_group!(benches, bench_log2, bench_exp, bench_exp2, bench_atan, bench_atan2); +criterion_group!(benches, bench_log2, bench_log2_1p, + bench_exp, bench_exp2, bench_exp_m1, bench_exp2_m1, + bench_atan, bench_atan2); criterion_main!(benches); diff --git a/examples/exhaustive-exp_m1.rs b/examples/exhaustive-exp_m1.rs new file mode 100644 index 0000000..ada56b0 --- /dev/null +++ b/examples/exhaustive-exp_m1.rs @@ -0,0 +1,32 @@ +extern crate fast_math; +extern crate ieee754; +use ieee754::Ieee754; + +use std::f32::consts::LN_2; + +fn main() { + let mut max_rel = 0f32; + let mut max_abs = 0f32; + for x in (-128.0 * LN_2).upto(128.0 * LN_2) { + let e = fast_math::exp_m1(x); + let t = x.exp_m1(); + let diff = (e - t).abs(); + let rel = e.rel_error(t).abs(); + max_abs = max_abs.max(diff); + max_rel = max_rel.max(rel); + } + println!("exp_m1 : absolute: {:.8e}, relative: {:.8}", max_abs, max_rel); + + let (abs, rel) = (-128.0).upto(128.0) + .map(|x| { + let e = fast_math::exp2_m1(x); + let t = (x * LN_2).exp_m1(); + let diff = (e - t).abs(); + let rel = e.rel_error(t).abs(); + (diff, rel) + }) + .fold((0_f32, 0_f32), |(a, a_), (b, b_)| (a.max(b), a_.max(b_))); + + println!("exp2_m1: absolute: {:.8e}, relative: {:.8}", abs, rel); + +} diff --git a/examples/exhaustive-log2_1p.rs b/examples/exhaustive-log2_1p.rs new file mode 100644 index 0000000..089612d --- /dev/null +++ b/examples/exhaustive-log2_1p.rs @@ -0,0 +1,21 @@ +extern crate fast_math; +extern crate ieee754; +use ieee754::Ieee754; +use std::f64; + +fn exact_log2_1p(x: f32) -> f32 { + ((x as f64).ln_1p() * f64::consts::LOG2_E) as f32 +} + +fn main() { + let (abs, rel) = (-1.0).upto(std::f32::MAX) + .map(|x| { + let e = fast_math::log2_1p(x); + let t = exact_log2_1p(x); + let diff = (e - t).abs(); + (diff, e.rel_error(t).abs()) + }) + .fold((0_f32, 0_f32), |(a, a_), (b, b_)| (a.max(b), a_.max(b_))); + + println!("absolute: {:.8}, relative: {:.8}", abs, rel); +} diff --git a/optimiser/Cargo.toml b/optimiser/Cargo.toml new file mode 100644 index 0000000..b037418 --- /dev/null +++ b/optimiser/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "optimiser" +version = "0.1.0" +authors = ["Huon Wilson "] +edition = "2018" +publish = false # internal implementation detail + +[dependencies] +ieee754 = "0.2" +fast-math = { path = ".." } +optimize = { git = "https://github.com/to266/optimize" } +ndarray = "0.11" diff --git a/optimiser/src/main.rs b/optimiser/src/main.rs new file mode 100644 index 0000000..b59517e --- /dev/null +++ b/optimiser/src/main.rs @@ -0,0 +1,117 @@ +use ndarray::prelude::*; +use optimize::vector::{NelderMeadBuilder}; +use optimize::scalar::{GoldenRatioBuilder}; +use ieee754::Ieee754; +use std::env; + +mod problems; + +fn max_errors(approx: impl IntoIterator, + exact: impl IntoIterator) -> (f64, f64) { + let mut rel = 0.0; + let mut abs = 0.0; + for (x, y) in approx.into_iter().zip(exact) { + rel = (x as f64).rel_error(y).abs().max(rel); + abs = (x as f64 - y).abs().max(abs); + } + (rel, abs) +} + +trait Approximation { + /// Name of the function this is approximating + fn name() -> &'static str; + + /// The number of parameters to optimize + const NUM_PARAMS: usize; + /// The ranges (min, max, initial guess) for each parameter. + fn ranges() -> Vec<(f32, f32, Option)>; + + /// The minimum value to test relative accuracy + const MIN: f32; + /// The maximum value to test relative accuracy + const MAX: f32; + /// Any specific values that should be included in the relative + /// accuracy testing, in case the automatic selection doesn't + /// include them. + fn exact_test_values() -> Vec { vec![] } + + /// The "exact" value of the approximated function at `x`. + fn exact(x: f64) -> f64; + /// The value of the approximation at `x` using parameters + /// `params`. + fn approx(x: f32, params: ArrayView1) -> f32; +} + +fn run(_a: A, num_test_values: usize) { + let lin_test = Array::linspace(A::MIN, A::MAX, num_test_values); + let mut test_values = lin_test.to_vec(); + test_values.extend(A::exact_test_values()); + + let mut guesses = Array::zeros((A::NUM_PARAMS, 3)); + + let ranges = A::ranges(); + assert_eq!(ranges.len(), A::NUM_PARAMS); + for ((min, max, init), mut row) in ranges.into_iter().zip(guesses.genrows_mut()) { + row[0] = min as f64; + row[1] = max as f64; + row[2] = init.unwrap_or((min + max) / 2.0) as f64; + } + + if A::NUM_PARAMS == 1 { + let minimizer = GoldenRatioBuilder::default() + .xtol(1e-8) + .max_iter(50000) + .build() + .unwrap(); + + let func = |point: f64| { + let slice = &[point]; + let view = ArrayView::from_shape(1, slice).unwrap(); + let approx = test_values.iter().map(|x| A::approx(*x, view)); + let exact = test_values.iter().map(|x| A::exact(*x as f64)); + + let (rel, _abs) = max_errors(approx, exact); + rel + }; + let result = minimizer.minimize_bracket(&func, guesses[(0, 0)], guesses[(0, 1)]); + + let error = func(result); + println!("{:10} (rel error = {:.5e}): {:<12}", A::name(), error, result as f32); + } else { + let minimizer = NelderMeadBuilder::default() + .xtol(1e-8) + .ftol(1e-8) + .maxiter(50000) + .build() + .unwrap(); + + let func = |view: ArrayView1| { + let approx = test_values.iter().map(|x| A::approx(*x, view)); + let exact = test_values.iter().map(|x| A::exact(*x as f64)); + + let (rel, _abs) = max_errors(approx, exact); + println!("{} {}", view, rel); + rel + }; + let result = minimizer.minimize(&func, guesses.column(2)); + let error = func(result.view()); + println!("{:10} (rel error = {:.5e}): {:<12}", A::name(), error, + result.map(|x| *x as f32)); + } +} + +fn main() { + let n = 1_000_000; + for name in env::args().skip(1) { + match name.as_str() { + "atan" => run(problems::Atan, n), + "exp" => run(problems::Exp, n), + "exp2" => run(problems::Exp2, n), + "exp_m1" => run(problems::ExpM1, n), + "log2" => run(problems::Log2, n), + "log2_1p" => run(problems::Log2_1p, n), + "log_1p" => run(problems::Log_1p, n), + s => panic!("unknown argument '{}'", s), + } + } +} diff --git a/optimiser/src/problems.rs b/optimiser/src/problems.rs new file mode 100644 index 0000000..dd5d5b3 --- /dev/null +++ b/optimiser/src/problems.rs @@ -0,0 +1,221 @@ +use ndarray::prelude::*; +use crate::Approximation; +use ieee754::Ieee754; +use std::f32::{self, consts}; +use std::f64; + +pub struct Exp; +impl Approximation for Exp { + fn name() -> &'static str { "exp" } + + const NUM_PARAMS: usize = 3; + fn ranges() -> Vec<(f32, f32, Option)> { + vec![(0.0, 3.0, Some(0.3371894346)), + (0.0, 3.0, Some(0.657636276)), + (0.0, 3.0, Some(1.00172476))] + } + + const MIN: f32 = -87.0; + const MAX: f32 = 87.0; + fn exact_test_values() -> Vec { + vec![0.0, 1.0] + } + + fn exact(x: f64) -> f64 { + x.exp() + } + + fn approx(x: f32, params: ArrayView1) -> f32 { + assert_eq!(params.len(), Self::NUM_PARAMS); + + const A: f32 = (1 << 23) as f32; + const MASK: i32 = 0xff800000u32 as i32; + const EXP2_23: f32 = 1.1920929e-7; + let c0: f32 = params[0] as f32 * EXP2_23 * EXP2_23; + let c1: f32 = params[1] as f32 * EXP2_23; + let c2: f32 = params[2] as f32; + + let a = A * consts::LOG2_E; + let mul = (a * x) as i32; + let floor = mul & MASK; + let frac = (mul - floor) as f32; + + let approx = (c0 * frac + c1) * frac + c2; + f32::from_bits(approx.bits().wrapping_add(floor as u32)) + } +} + +pub struct Exp2; +impl Approximation for Exp2 { + fn name() -> &'static str { "exp2" } + + const NUM_PARAMS: usize = 3; + fn ranges() -> Vec<(f32, f32, Option)> { + vec![(0.0, 3.0, Some(0.3371894346)), + (0.0, 3.0, Some(0.657636276)), + (0.0, 3.0, Some(1.00172476))] + } + + const MIN: f32 = -87.0; + const MAX: f32 = 87.0; + fn exact_test_values() -> Vec { + vec![0.0, 1.0] + } + + fn exact(x: f64) -> f64 { + x.exp2() + } + + fn approx(x: f32, params: ArrayView1) -> f32 { + assert_eq!(params.len(), Self::NUM_PARAMS); + + const A: f32 = (1 << 23) as f32; + const MASK: i32 = 0xff800000u32 as i32; + const EXP2_23: f32 = 1.1920929e-7; + let c0: f32 = params[0] as f32 * EXP2_23 * EXP2_23; + let c1: f32 = params[1] as f32 * EXP2_23; + let c2: f32 = params[2] as f32; + + let a = A; + let mul = (a * x) as i32; + let floor = mul & MASK; + let frac = (mul - floor) as f32; + + let approx = (c0 * frac + c1) * frac + c2; + f32::from_bits(approx.bits().wrapping_add(floor as u32)) + } +} + +pub struct ExpM1; +impl Approximation for ExpM1 { + fn name() -> &'static str { "exp_m1" } + + const NUM_PARAMS: usize = 3; + fn ranges() -> Vec<(f32, f32, Option)> { + vec![(0.0, 1.0, Some(0.2)), + (0.0, 2.0, Some(1.0)), + (0.0, 1.0, Some(0.5))] + } + + const MIN: f32 = -1.0; + const MAX: f32 = 1.0; + fn exact_test_values() -> Vec { + vec![0.0] + } + + fn exact(x: f64) -> f64 { + x.exp_m1() + } + fn approx(x: f32, params: ArrayView1) -> f32 { + assert_eq!(params.len(), Self::NUM_PARAMS); + let limit = params[0] as f32; + let add = params[1] as f32; + let mul = params[2] as f32; + + let value = if x.abs() <= limit { + x * (add + mul * x) + } else { + fast_math::exp(x) - 1.0 + }; + value + } +} + +pub struct Log2; +impl Approximation for Log2 { + fn name() -> &'static str { "log2" } + + const NUM_PARAMS: usize = 2; + fn ranges() -> Vec<(f32, f32, Option)> { + vec![(-3.0, 0.0, Some(-0.6296735)), + (0.0, 3.0, Some(1.466967))] + } + + const MIN: f32 = f32::MIN_POSITIVE; + const MAX: f32 = 50.0; + + fn exact_test_values() -> Vec { + vec![1.0, 2.0] + } + + fn exact(x: f64) -> f64 { + x.log2() + } + + fn approx(x: f32, params: ArrayView1) -> f32 { + assert_eq!(params.len(), Self::NUM_PARAMS); + + let (_sign, exp, signif) = x.decompose_raw(); + debug_assert!(!_sign && 1 <= exp && exp <= 254); + + let high_bit = ((signif >> 22) & 1) as u8; + let add_exp = (exp + high_bit) as i32 - 127; + let normalised = f32::recompose_raw(false, 0x7F ^ high_bit, signif) - 1.0; + let a: f32 = params[0] as f32; + let b: f32 = params[1] as f32; + add_exp as f32 + normalised * (b + a * normalised) + } +} + +pub struct Log2_1p; +impl Approximation for Log2_1p { + fn name() -> &'static str { "log2_1p" } + + const NUM_PARAMS: usize = 1; + fn ranges() -> Vec<(f32, f32, Option)> { + vec![(0.0, 1.0, Some(1.0))] + } + + const MIN: f32 = -0.99999994; + const MAX: f32 = 1.0; + fn exact_test_values() -> Vec { + vec![-0.015, -1e-30, 0.0, 1e-30, 0.015, 1.0] + } + + fn exact(x: f64) -> f64 { + x.ln_1p() * f64::consts::LOG2_E + } + + fn approx(x: f32, params: ArrayView1) -> f32 { + assert_eq!(params.len(), Self::NUM_PARAMS); + let limit = params[0] as f32; + + let value = if x.abs() <= limit { + x * f32::consts::LOG2_E + } else { + fast_math::log2(1.0 + x) + }; + value + } +} + +pub struct Atan; +impl Approximation for Atan { + fn name() -> &'static str { "atan" } + + const NUM_PARAMS: usize = 2; + fn ranges() -> Vec<(f32, f32, Option)> { + let n2 = 0.273; + vec![(0.0, 2.0, Some(consts::FRAC_PI_4 + n2)), + (0.0, 2.0, Some(n2))] + } + + const MIN: f32 = -1.0; + const MAX: f32 = 1.0; + fn exact_test_values() -> Vec { + vec![-1.0, 0.0, 1.0] + } + + fn exact(x: f64) -> f64 { + x.atan() + } + + fn approx(x: f32, params: ArrayView1) -> f32 { + assert_eq!(params.len(), Self::NUM_PARAMS); + + let add = params[0] as f32; + let mul = params[1] as f32; + + (add - mul * x.abs()) * x + } +} diff --git a/src/exp.rs b/src/exp.rs index 0cb42c5..7611e8b 100644 --- a/src/exp.rs +++ b/src/exp.rs @@ -16,6 +16,13 @@ impl Base { Base::Two => 1.0, } } + #[inline(always)] + fn ln(self) -> f32 { + match self { + Base::E => 1.0, + Base::Two => f::LN_2, + } + } #[inline(always)] fn upper_limit(self) -> f32 { @@ -59,6 +66,33 @@ fn exp_impl(x: f32, base: Base) -> f32 { } } +const EXP_M1_THRESHOLD: f32 = 0.25153902; +const EXP_M1_ADD: f32 = 1.0053172; +const EXP_M1_MUL: f32 = 0.5004446; +#[inline(always)] +fn exp_m1_raw_impl(x: f32, base: Base) -> f32 { + if x.abs() <= EXP_M1_THRESHOLD / base.ln() { + // premultiply because these can be done at compile time + let add = EXP_M1_ADD * base.ln(); + let mul = EXP_M1_MUL * base.ln() * base.ln(); + x * (add + mul * x) + } else { + exp_raw_impl(x, base) - 1.0 + } +} + +#[inline(always)] +fn exp_m1_impl(x: f32, base: Base) -> f32 { + if x.abs() <= EXP_M1_THRESHOLD / base.ln() { + // premultiply because these can be done at compile time + let add = EXP_M1_ADD * base.ln(); + let mul = EXP_M1_MUL * base.ln() * base.ln(); + x * (add + mul * x) + } else { + exp_impl(x, base) - 1.0 + } +} + /// Compute a fast approximation to 2x for /// -151 ≤ `x` ≤ 151. /// @@ -89,6 +123,32 @@ pub fn exp2(x: f32) -> f32 { exp_impl(x, Base::Two) } +/// Compute a fast approximation to 2x - 1 for +/// -128 ≤ `x` ≤ 128. +/// +/// This will return unspecified nonsense if `x` does not satisfy +/// those requirements. Use `exp2_m1` if correct handling is required +/// (at the expense of some speed). +/// +/// The maximum relative error is less than 0.011. +#[inline] +pub fn exp2_m1_raw(x: f32) -> f32 { + exp_m1_raw_impl(x, Base::Two) +} + +/// Compute a fast approximation to 2x - 1. +/// +/// The maximum relative error is less than 0.011. +/// +/// If `x` is NaN, `exp2_m1` returns NaN. +/// +/// See also `exp2_m1_raw` which only works on -128 ≤ `x` ≤ 128, +/// but is 10-50% faster. +#[inline] +pub fn exp2_m1(x: f32) -> f32 { + exp_m1_impl(x, Base::Two) +} + /// Compute a fast approximation to *e*x for /// -104 ≤ `x` ≤ 104. /// @@ -121,6 +181,32 @@ pub fn exp(x: f32) -> f32 { exp_impl(x, Base::E) } +/// Compute a fast approximation to *e*x - 1 for +/// -88 ≤ `x` ≤ 88. +/// +/// This will return unspecified nonsense if `x` does not satisfy +/// those requirements. Use `exp_m1` if correct handling is required +/// (at the expense of some speed). +/// +/// The maximum relative error is less than 0.011. +#[inline] +pub fn exp_m1_raw(x: f32) -> f32 { + exp_m1_raw_impl(x, Base::E) +} + +/// Compute a fast approximation to *e*x - 1. +/// +/// The maximum relative error is less than 0.011. +/// +/// If `x` is NaN, `exp_m1` returns NaN. +/// +/// See also `exp_m1_raw` which only works on -88 ≤ `x` ≤ 88, +/// but is 10-30% faster. +#[inline] +pub fn exp_m1(x: f32) -> f32 { + exp_m1_impl(x, Base::E) +} + #[cfg(test)] mod tests { use super::*; @@ -142,7 +228,8 @@ mod tests { if t.classify() == num::FpCategory::Subnormal { // subnormal should be approximately right assert!(rel <= 1.0, - "{:.8}: e = {:.8e}, t = {:.8e}. {:.4}", x, e, t, rel); } else { + "{:.8}: e = {:.8e}, t = {:.8e}. {:.4}", x, e, t, rel); + } else { if rel > max { max = rel } // e == t handles the infinity case assert!(rel <= 0.002, @@ -167,7 +254,8 @@ mod tests { if t.classify() == num::FpCategory::Subnormal { // subnormal should be approximately right assert!(rel <= 1.0, - "{:.8}: e = {:.8e}, t = {:.8e}. {:.4}", x, e, t, rel); } else { + "{:.8}: e = {:.8e}, t = {:.8e}. {:.4}", x, e, t, rel); + } else { if rel > max { max = rel } // e == t handles the infinity case assert!(rel <= 0.002, @@ -194,4 +282,74 @@ mod tests { assert!((exp2(0.0) - 1.0).abs() < 0.002); assert_eq!(exp2(f32::INFINITY), f32::INFINITY); } + + const EXP_M1_REL_ERR: f32 = 0.0054; + #[test] + fn exp_m1_rel_err_exhaustive() { + let mut max = 0.0; + for i in 0..PREC + 1 { + for j in -5..6 { + for &sign in &[-1.0, 1.0] { + let x = sign * (1.0 + i as f32 / PREC as f32) * 2f32.powi(j * 2); + let e = exp_m1(x); + let t = x.exp_m1(); + let rel = e.rel_error(t).abs(); + + if t.classify() == num::FpCategory::Subnormal { + // subnormal should be approximately right + assert!(rel <= 1.0, + "{:.8}: e = {:.8e}, t = {:.8e}. {:.4}", x, e, t, rel); + } else { + if rel > max { max = rel } + // e == t handles the infinity case + assert!(rel <= EXP_M1_REL_ERR, + "{:.8}: e = {:.8e}, t = {:.8e}. {:.4}", x, e, t, rel); + } + } + } + } + println!("maximum {}", max); + } + + #[test] + fn exp2_m1_rel_err_exhaustive() { + let mut max = 0.0; + for i in 0..PREC + 1 { + for j in -5..6 { + for &sign in &[-1.0, 1.0] { + let x = sign * (1.0 + i as f32 / PREC as f32) * 2f32.powi(j * 2); + let e = exp2_m1(x); + let t = (x * f32::consts::LN_2).exp_m1(); + let rel = e.rel_error(t).abs(); + if t.classify() == num::FpCategory::Subnormal { + // subnormal should be approximately right + assert!(rel <= 1.0, + "{:.8}: e = {:.8e}, t = {:.8e}. {:.4}", x, e, t, rel); + } else { + if rel > max { max = rel } + // e == t handles the infinity case + assert!(rel <= EXP_M1_REL_ERR, + "{:.8}: e = {:.8e}, t = {:.8e}. {:.4}", x, e, t, rel); + } + } + } + } + println!("maximum {}", max); + } + + #[test] + fn exp_m1_edge_cases() { + assert!(exp_m1(f32::NAN).is_nan()); + assert_eq!(exp_m1(f32::NEG_INFINITY), -1.0); + assert_eq!(exp_m1(0.0), 0.0); + assert_eq!(exp_m1(f32::INFINITY), f32::INFINITY); + } + + #[test] + fn exp2_m1_edge_cases() { + assert!(exp2_m1(f32::NAN).is_nan()); + assert_eq!(exp2_m1(f32::NEG_INFINITY), -1.0); + assert_eq!(exp2_m1(0.0), 0.0); + assert_eq!(exp2_m1(f32::INFINITY), f32::INFINITY); + } } diff --git a/src/lib.rs b/src/lib.rs index be0fce6..1ed1ccd 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,8 +30,10 @@ extern crate ieee754; pub use log::{log2, log2_raw}; +pub use log::{log2_1p, log2_1p_raw}; pub use atan::{atan_raw, atan, atan2}; pub use exp::{exp_raw, exp2_raw, exp, exp2}; +pub use exp::{exp_m1_raw, exp_m1, exp2_m1_raw, exp2_m1}; mod log; mod atan; diff --git a/src/log.rs b/src/log.rs index b4e8b49..c056727 100644 --- a/src/log.rs +++ b/src/log.rs @@ -43,7 +43,7 @@ fn log2_exp_0(signif: u32) -> f32 { } else { // denormal let zeros = signif.leading_zeros() - 9 + 1; - -126.0 - zeros as f32 + log2(f32::recompose_raw(false, 127, signif << zeros)) + -126.0 - (zeros as f32) + log2(f32::recompose_raw(false, 127, signif << zeros)) } } @@ -75,11 +75,48 @@ pub fn log2_raw(x: f32) -> f32 { add_exp as f32 + normalised * (B + A * normalised) } +const LOG2_1P_LIMIT: f32 = 0.04277497; +/// Compute a fast approximation of the base-2 logarithm of `1 + x` +/// for -1 < `x` < ∞. +/// +/// This will return unspecified nonsense if `x` is doesn't not +/// satisfy those constraints. Use `log2_1p` if correct handling is +/// required (at the expense of some speed). +/// +/// The maximum relative error across all valid input is less than +/// 0.022. The maximum absolute error is less than 0.009. +#[inline] +pub fn log2_1p(x: f32) -> f32 { + if x.abs() < LOG2_1P_LIMIT { + x * f::consts::LOG2_E + } else { + log2(1.0 + x) + } +} + +/// Compute a fast approximation of the base-2 logarithm of `1 + x` +/// for -1 < `x` < ∞. +/// +/// This will return unspecified nonsense if `x` is doesn't not +/// satisfy those constraints. Use `log2_1p` if correct handling is +/// required (at the expense of some speed). +/// +/// The maximum relative error across all valid input is less than +/// 0.022. The maximum absolute error is less than 0.009. +#[inline] +pub fn log2_1p_raw(x: f32) -> f32 { + if x.abs() < LOG2_1P_LIMIT { + x * f::consts::LOG2_E + } else { + log2_raw(1.0 + x) + } +} + #[cfg(test)] mod tests { use super::*; use quickcheck as qc; - use std::f32 as f; + use std::{f32 as f, f64}; use ieee754::Ieee754; #[test] @@ -113,7 +150,7 @@ mod tests { } #[test] - fn edge_cases() { + fn log2_edge_cases() { assert!(log2(f::NAN).is_nan()); assert!(log2(-1.0).is_nan()); assert!(log2(f::NEG_INFINITY).is_nan()); @@ -123,7 +160,7 @@ mod tests { } #[test] - fn denormals() { + fn log2_denormals() { fn prop(x: u8, y: u16) -> bool { let signif = ((x as u32) << 16) | (y as u32); let mut x = f32::recompose_raw(false, 1, signif); @@ -143,4 +180,53 @@ mod tests { } qc::quickcheck(prop as fn(u8, u16) -> bool) } + + fn exact_log2_1p(x: f32) -> f32 { + ((x as f64).ln_1p() * f64::consts::LOG2_E) as f32 + } + #[test] + fn log2_1p_rel_err_qc() { + fn prop(x: f32) -> qc::TestResult { + if !(x > 1.0) { return qc::TestResult::discard() } + + let e = log2_1p(x); + let t = exact_log2_1p(x); + + qc::TestResult::from_bool(e.rel_error(t).abs() < 0.025) + } + qc::quickcheck(prop as fn(f32) -> qc::TestResult) + } + + #[test] + fn log2_1p_rel_err_exhaustive() { + let mut max = 0.0; + for i in 0..PREC + 1 { + for &sign in &[-1.0, 1.0] { + let upper = if sign > 0.0 { 6 } else { 0 }; + for j in -5..upper { + let x = sign * (1.0 + i as f32 / PREC as f32) * 2f32.powi(j * 20); + let e = log2_1p(x); + let t = exact_log2_1p(x); + let rel = e.rel_error(t).abs(); + if rel > max { max = rel } + assert!(rel < 0.025 && (e - t).abs() < 0.009, + "{:.8}: {:.8}, {:.8}. {:.4}", x, e, t, rel); + } + } + } + println!("maximum {}", max); + } + + #[test] + fn log2_1p_edge_cases() { + assert!(log2_1p(f::NAN).is_nan()); + assert!(log2_1p(f::NEG_INFINITY).is_nan()); + assert!(log2_1p(-2.0).is_nan()); + assert_eq!(log2_1p(-1.0), f::NEG_INFINITY); + assert_eq!(log2_1p(0.0), 0.0); + let denormal = f32::recompose_raw(false, 0, 1); + assert_eq!(log2_1p(denormal), denormal); + assert_eq!(log2_1p(1.0), 1.0); + assert_eq!(log2_1p(f::INFINITY), f::INFINITY); + } }