Skip to content

Fast paths for ExactReal with BareInterval - #773

Open
timholy wants to merge 1 commit into
JuliaIntervals:masterfrom
timholy:teh/fastexact
Open

Fast paths for ExactReal with BareInterval#773
timholy wants to merge 1 commit into
JuliaIntervals:masterfrom
timholy:teh/fastexact

Conversation

@timholy

@timholy timholy commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

An ExactReal is a point, so +, -, *, / and \ against a BareInterval of the same number type apply the operation to the two endpoints directly, rather than promoting the point to a thin interval and running the interval-interval operator on it.

Each method takes that route only where it is bitwise identical to the promotion, and delegates the rest: a non-finite point, whose thin interval is ill-formed; an unbounded interval under *, where 0 * Inf is flavor dependent; and division by a zero point. Rounding still goes through @round, so the results are unchanged under every rounding mode. Mixed number types keep the promotion, which is where the point is rounded to the interval's number type.

The type parameter is bounded by NumTypes so that these methods are more specific than the generic ExactReal/BareInterval methods, whose own parameters are bounded by Real and NumTypes; the tests assert that dispatch selects them.

Point times interval costs 3.2 ns against the promotion route's 6.4-8.2 ns with rounding :none, and 6.7 ns against 9.1-10.2 ns with :correct.

Assisted-by: Claude Opus 5 (claude-opus-5) noreply@anthropic.com

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results (Julia v1)

Time benchmarks
master 21ce1b7... master / 21ce1b7...
BigFloat MPFI/basics/* 25.4 ± 3.7 μs 24.8 ± 3.6 μs 1.02 ± 0.21
BigFloat MPFI/basics/+ 12.4 ± 3.5 μs 12.9 ± 3.4 μs 0.965 ± 0.37
BigFloat MPFI/basics/- 17.6 ± 3.4 μs 18.3 ± 3.5 μs 0.959 ± 0.26
BigFloat MPFI/basics// 19.7 ± 3.7 μs 19.8 ± 4.3 μs 0.997 ± 0.29
BigFloat MPFI/basics/abs 10.6 ± 3.4 μs 10.5 ± 3.4 μs 1.01 ± 0.46
BigFloat MPFI/basics/acos 0.675 ± 0.0085 ms 0.676 ± 0.0088 ms 0.999 ± 0.018
BigFloat MPFI/basics/asin 0.656 ± 0.0091 ms 0.656 ± 0.0092 ms 1 ± 0.02
BigFloat MPFI/basics/atan 2.1 ± 0.0073 ms 2.09 ± 0.0078 ms 1 ± 0.0051
BigFloat MPFI/basics/cos 0.361 ± 0.01 ms 0.366 ± 0.0099 ms 0.986 ± 0.038
BigFloat MPFI/basics/cosh 0.433 ± 0.012 ms 0.434 ± 0.012 ms 0.998 ± 0.039
BigFloat MPFI/basics/exp 0.504 ± 0.011 ms 0.506 ± 0.01 ms 0.996 ± 0.029
BigFloat MPFI/basics/inv 18.9 ± 3.5 μs 19 ± 3.5 μs 0.997 ± 0.26
BigFloat MPFI/basics/log 0.47 ± 0.011 ms 0.473 ± 0.0099 ms 0.994 ± 0.031
BigFloat MPFI/basics/sin 0.468 ± 0.011 ms 0.474 ± 0.011 ms 0.987 ± 0.033
BigFloat MPFI/basics/sinh 0.573 ± 0.01 ms 0.572 ± 0.011 ms 1 ± 0.025
BigFloat MPFI/basics/sqrt 27.9 ± 6.8 μs 27.3 ± 6.8 μs 1.02 ± 0.36
BigFloat MPFI/basics/tan 0.387 ± 0.01 ms 0.39 ± 0.01 ms 0.992 ± 0.037
BigFloat MPFI/basics/tanh 0.586 ± 0.011 ms 0.585 ± 0.01 ms 1 ± 0.025
BigFloat bareinterval/basics/* 0.0394 ± 0.0028 ms 0.0406 ± 0.0027 ms 0.971 ± 0.095
BigFloat bareinterval/basics/+ 22.5 ± 3.4 μs 21.9 ± 3.3 μs 1.03 ± 0.22
BigFloat bareinterval/basics/- 22.5 ± 3.2 μs 22.1 ± 3.3 μs 1.01 ± 0.21
BigFloat bareinterval/basics// 19.2 ± 5.1 μs 19.2 ± 5.1 μs 0.998 ± 0.37
BigFloat bareinterval/basics/abs 15.2 ± 3.1 μs 15.2 ± 3.1 μs 0.998 ± 0.29
BigFloat bareinterval/basics/acos 0.708 ± 0.023 ms 0.707 ± 0.023 ms 1 ± 0.046
BigFloat bareinterval/basics/asin 0.69 ± 0.021 ms 0.689 ± 0.021 ms 1 ± 0.044
BigFloat bareinterval/basics/atan 2.11 ± 0.0079 ms 2.12 ± 0.0093 ms 0.995 ± 0.0057
BigFloat bareinterval/basics/cos 0.344 ± 0.085 ms 0.346 ± 0.087 ms 0.994 ± 0.35
BigFloat bareinterval/basics/cosh 0.476 ± 0.022 ms 0.476 ± 0.021 ms 1 ± 0.064
BigFloat bareinterval/basics/exp 0.512 ± 0.01 ms 0.514 ± 0.01 ms 0.996 ± 0.028
BigFloat bareinterval/basics/inv 26.5 ± 3.4 μs 27 ± 3.5 μs 0.981 ± 0.18
BigFloat bareinterval/basics/log 0.502 ± 0.012 ms 0.509 ± 0.012 ms 0.987 ± 0.033
BigFloat bareinterval/basics/sin 0.512 ± 0.094 ms 0.485 ± 0.096 ms 1.06 ± 0.28
BigFloat bareinterval/basics/sinh 0.581 ± 0.011 ms 0.581 ± 0.012 ms 0.999 ± 0.027
BigFloat bareinterval/basics/sqrt 0.0325 ± 0.0024 ms 0.0321 ± 0.0026 ms 1.01 ± 0.11
BigFloat bareinterval/basics/tan 0.298 ± 0.056 ms 0.326 ± 0.056 ms 0.915 ± 0.23
BigFloat bareinterval/basics/tanh 0.594 ± 0.011 ms 0.595 ± 0.011 ms 0.999 ± 0.025
BigFloat interval/basics/* 0.0413 ± 0.0019 ms 0.0434 ± 0.0019 ms 0.953 ± 0.06
BigFloat interval/basics/+ 25.2 ± 9.1 μs 24.5 ± 8.4 μs 1.03 ± 0.51
BigFloat interval/basics/- 24.6 ± 8.2 μs 24.3 ± 8.2 μs 1.01 ± 0.48
BigFloat interval/basics// 23.9 ± 4.9 μs 24.2 ± 4.9 μs 0.99 ± 0.28
BigFloat interval/basics/abs 14.2 ± 7.7 μs 14.2 ± 7.7 μs 0.998 ± 0.76
BigFloat interval/basics/acos 0.707 ± 0.039 ms 0.705 ± 0.042 ms 1 ± 0.082
BigFloat interval/basics/asin 0.686 ± 0.033 ms 0.69 ± 0.035 ms 0.995 ± 0.069
BigFloat interval/basics/atan 2.12 ± 0.0079 ms 2.11 ± 0.0091 ms 1 ± 0.0057
BigFloat interval/basics/cos 0.338 ± 0.013 ms 0.34 ± 0.014 ms 0.994 ± 0.058
BigFloat interval/basics/cosh 0.468 ± 0.021 ms 0.468 ± 0.02 ms 1 ± 0.061
BigFloat interval/basics/exp 0.522 ± 0.0099 ms 0.522 ± 0.01 ms 0.999 ± 0.027
BigFloat interval/basics/inv 30.2 ± 7 μs 30.9 ± 5.9 μs 0.976 ± 0.29
BigFloat interval/basics/log 0.503 ± 0.037 ms 0.509 ± 0.036 ms 0.987 ± 0.1
BigFloat interval/basics/sin 0.489 ± 0.024 ms 0.489 ± 0.018 ms 0.999 ± 0.061
BigFloat interval/basics/sinh 0.59 ± 0.01 ms 0.591 ± 0.011 ms 0.998 ± 0.025
BigFloat interval/basics/sqrt 0.04 ± 0.029 ms 0.0397 ± 0.03 ms 1.01 ± 1.1
BigFloat interval/basics/tan 0.283 ± 0.014 ms 0.283 ± 0.014 ms 1 ± 0.07
BigFloat interval/basics/tanh 0.603 ± 0.011 ms 0.605 ± 0.011 ms 0.997 ± 0.026
bareinterval/basics/* 1.74 ± 0.049 μs 1.75 ± 0.059 μs 0.994 ± 0.044
bareinterval/basics/+ 0.491 ± 0.01 μs 0.532 ± 0.01 μs 0.923 ± 0.026
bareinterval/basics/- 0.511 ± 0.01 μs 0.531 ± 0.021 μs 0.962 ± 0.042
bareinterval/basics// 1.21 ± 0.031 μs 1.21 ± 0.03 μs 1 ± 0.036
bareinterval/basics/abs 0.191 ± 0.021 μs 0.201 ± 0.011 μs 0.95 ± 0.12
bareinterval/basics/acos 2.71 ± 0.03 μs 2.73 ± 0.02 μs 0.996 ± 0.013
bareinterval/basics/asin 3.01 ± 0.029 μs 3.05 ± 0.041 μs 0.987 ± 0.016
bareinterval/basics/atan 13.2 ± 0.18 μs 13 ± 0.18 μs 1.02 ± 0.02
bareinterval/basics/cos 0.0503 ± 0.00083 ms 0.051 ± 0.001 ms 0.986 ± 0.026
bareinterval/basics/cosh 7.18 ± 0.031 μs 7.18 ± 0.031 μs 1 ± 0.0061
bareinterval/basics/exp 4.26 ± 0.05 μs 4.26 ± 0.05 μs 1 ± 0.017
bareinterval/basics/inv 1.04 ± 0.021 μs 1 ± 0.02 μs 1.04 ± 0.029
bareinterval/basics/log 1.94 ± 0.021 μs 6.13 ± 4.2 μs 0.317 ± 0.22
bareinterval/basics/sin 0.0493 ± 0.018 ms 0.0499 ± 0.018 ms 0.987 ± 0.51
bareinterval/basics/sinh 10 ± 0.051 μs 10 ± 0.06 μs 1 ± 0.0079
bareinterval/basics/sqrt 1.14 ± 0.011 μs 1.12 ± 0.01 μs 1.02 ± 0.013
bareinterval/basics/tan 28.8 ± 0.29 μs 29.2 ± 0.35 μs 0.986 ± 0.015
bareinterval/basics/tanh 0.297 ± 0.0091 ms 0.297 ± 0.0091 ms 1 ± 0.043
interval/basics/* 2.81 ± 0.051 μs 2.87 ± 0.07 μs 0.983 ± 0.03
interval/basics/+ 1.33 ± 0.039 μs 1.33 ± 0.04 μs 1 ± 0.042
interval/basics/- 1.38 ± 0.03 μs 1.39 ± 0.09 μs 0.993 ± 0.068
interval/basics// 1.89 ± 0.04 μs 1.89 ± 0.049 μs 1 ± 0.033
interval/basics/abs 0.41 ± 0.04 μs 0.351 ± 0.049 μs 1.17 ± 0.2
interval/basics/acos 3.28 ± 0.05 μs 3.3 ± 0.08 μs 0.994 ± 0.028
interval/basics/asin 3.55 ± 0.031 μs 3.56 ± 0.049 μs 0.997 ± 0.016
interval/basics/atan 12 ± 0.14 μs 13.6 ± 0.27 μs 0.884 ± 0.02
interval/basics/cos 0.0685 ± 0.0035 ms 0.0699 ± 0.0035 ms 0.98 ± 0.07
interval/basics/cosh 8.98 ± 0.06 μs 9.03 ± 0.06 μs 0.995 ± 0.0094
interval/basics/exp 4.9 ± 0.05 μs 4.88 ± 0.05 μs 1 ± 0.015
interval/basics/inv 1.48 ± 0.06 μs 1.53 ± 0.06 μs 0.967 ± 0.054
interval/basics/log 6.91 ± 0.07 μs 6.93 ± 0.07 μs 0.997 ± 0.014
interval/basics/sin 0.0671 ± 0.0034 ms 0.069 ± 0.0036 ms 0.973 ± 0.071
interval/basics/sinh 10.6 ± 0.089 μs 10.7 ± 0.13 μs 0.993 ± 0.015
interval/basics/sqrt 1.63 ± 0.08 μs 1.57 ± 0.04 μs 1.04 ± 0.057
interval/basics/tan 0.0389 ± 0.0019 ms 0.0394 ± 0.0018 ms 0.987 ± 0.066
interval/basics/tanh 0.309 ± 0.0077 ms 0.309 ± 0.0074 ms 0.997 ± 0.034
time_to_load 0.117 ± 0.00038 s 0.111 ± 0.0012 s 1.05 ± 0.012
Memory benchmarks
master 21ce1b7... master / 21ce1b7...
BigFloat MPFI/basics/* 0.424 k allocs: 21.3 kB 0.424 k allocs: 21.3 kB 1
BigFloat MPFI/basics/+ 0.302 k allocs: 16.5 kB 0.302 k allocs: 16.5 kB 1
BigFloat MPFI/basics/- 0.402 k allocs: 20.4 kB 0.402 k allocs: 20.4 kB 1
BigFloat MPFI/basics// 0.345 k allocs: 18.2 kB 0.345 k allocs: 18.2 kB 1
BigFloat MPFI/basics/abs 0.324 k allocs: 17.4 kB 0.324 k allocs: 17.4 kB 1
BigFloat MPFI/basics/acos 1.24 k allocs: 0.0445 MB 1.24 k allocs: 0.0445 MB 1
BigFloat MPFI/basics/asin 1.08 k allocs: 0.0355 MB 1.08 k allocs: 0.0355 MB 1
BigFloat MPFI/basics/atan 2.14 k allocs: 0.0543 MB 2.14 k allocs: 0.0543 MB 1
BigFloat MPFI/basics/cos 2.9 k allocs: 0.0975 MB 2.9 k allocs: 0.0975 MB 1
BigFloat MPFI/basics/cosh 0.781 k allocs: 0.0322 MB 0.781 k allocs: 0.0322 MB 1
BigFloat MPFI/basics/exp 0.902 k allocs: 0.036 MB 0.902 k allocs: 0.036 MB 1
BigFloat MPFI/basics/inv 0.351 k allocs: 18.4 kB 0.351 k allocs: 18.4 kB 1
BigFloat MPFI/basics/log 0.407 k allocs: 20.6 kB 0.407 k allocs: 20.6 kB 1
BigFloat MPFI/basics/sin 3.18 k allocs: 0.106 MB 3.18 k allocs: 0.106 MB 1
BigFloat MPFI/basics/sinh 0.915 k allocs: 0.0369 MB 0.915 k allocs: 0.0369 MB 1
BigFloat MPFI/basics/sqrt 0.302 k allocs: 16.5 kB 0.302 k allocs: 16.5 kB 1
BigFloat MPFI/basics/tan 2.8 k allocs: 0.098 MB 2.8 k allocs: 0.098 MB 1
BigFloat MPFI/basics/tanh 0.908 k allocs: 0.0362 MB 0.908 k allocs: 0.0362 MB 1
BigFloat bareinterval/basics/* 0.262 k allocs: 26 kB 0.262 k allocs: 26 kB 1
BigFloat bareinterval/basics/+ 0.202 k allocs: 20.4 kB 0.202 k allocs: 20.4 kB 1
BigFloat bareinterval/basics/- 0.202 k allocs: 20.4 kB 0.202 k allocs: 20.4 kB 1
BigFloat bareinterval/basics// 0.1 k allocs: 10.8 kB 0.1 k allocs: 10.8 kB 1
BigFloat bareinterval/basics/abs 0.199 k allocs: 20.1 kB 0.199 k allocs: 20.1 kB 1
BigFloat bareinterval/basics/acos 1.27 k allocs: 0.0692 MB 1.27 k allocs: 0.0692 MB 1
BigFloat bareinterval/basics/asin 1.17 k allocs: 0.0597 MB 1.17 k allocs: 0.0597 MB 1
BigFloat bareinterval/basics/atan 2.04 k allocs: 0.08 MB 2.04 k allocs: 0.08 MB 1
BigFloat bareinterval/basics/cos 2.45 k allocs: 0.185 MB 2.45 k allocs: 0.185 MB 1
BigFloat bareinterval/basics/cosh 1.01 k allocs: 0.0671 MB 1.01 k allocs: 0.0671 MB 1
BigFloat bareinterval/basics/exp 0.802 k allocs: 0.0397 MB 0.802 k allocs: 0.0397 MB 1
BigFloat bareinterval/basics/inv 0.198 k allocs: 20 kB 0.198 k allocs: 20 kB 1
BigFloat bareinterval/basics/log 0.616 k allocs: 0.0522 MB 0.616 k allocs: 0.0522 MB 1
BigFloat bareinterval/basics/sin 2.9 k allocs: 0.197 MB 2.9 k allocs: 0.197 MB 1
BigFloat bareinterval/basics/sinh 0.815 k allocs: 0.0407 MB 0.815 k allocs: 0.0407 MB 1
BigFloat bareinterval/basics/sqrt 0.26 k allocs: 25.8 kB 0.26 k allocs: 25.8 kB 1
BigFloat bareinterval/basics/tan 1.67 k allocs: 0.124 MB 1.67 k allocs: 0.124 MB 1
BigFloat bareinterval/basics/tanh 0.808 k allocs: 0.0399 MB 0.808 k allocs: 0.0399 MB 1
BigFloat interval/basics/* 0.263 k allocs: 26.8 kB 0.263 k allocs: 26.8 kB 1
BigFloat interval/basics/+ 0.203 k allocs: 21.2 kB 0.203 k allocs: 21.2 kB 1
BigFloat interval/basics/- 0.203 k allocs: 21.2 kB 0.203 k allocs: 21.2 kB 1
BigFloat interval/basics// 0.101 k allocs: 11.6 kB 0.101 k allocs: 11.6 kB 1
BigFloat interval/basics/abs 0.2 k allocs: 20.9 kB 0.2 k allocs: 20.9 kB 1
BigFloat interval/basics/acos 1.71 k allocs: 0.11 MB 1.71 k allocs: 0.11 MB 1
BigFloat interval/basics/asin 1.47 k allocs: 0.088 MB 1.47 k allocs: 0.0881 MB 0.999
BigFloat interval/basics/atan 2.04 k allocs: 0.0812 MB 2.04 k allocs: 0.0811 MB 1
BigFloat interval/basics/cos 2.45 k allocs: 0.186 MB 2.45 k allocs: 0.186 MB 1
BigFloat interval/basics/cosh 1.01 k allocs: 0.0681 MB 1.01 k allocs: 0.068 MB 1
BigFloat interval/basics/exp 0.803 k allocs: 0.0408 MB 0.803 k allocs: 0.0409 MB 0.999
BigFloat interval/basics/inv 0.199 k allocs: 20.8 kB 0.199 k allocs: 20.8 kB 1
BigFloat interval/basics/log 0.917 k allocs: 0.0805 MB 0.917 k allocs: 0.0805 MB 1
BigFloat interval/basics/sin 2.9 k allocs: 0.198 MB 2.9 k allocs: 0.198 MB 1
BigFloat interval/basics/sinh 0.816 k allocs: 0.0417 MB 0.816 k allocs: 0.0419 MB 0.997
BigFloat interval/basics/sqrt 0.714 k allocs: 0.0675 MB 0.714 k allocs: 0.0675 MB 1
BigFloat interval/basics/tan 1.67 k allocs: 0.125 MB 1.67 k allocs: 0.125 MB 1
BigFloat interval/basics/tanh 0.809 k allocs: 0.041 MB 0.809 k allocs: 0.041 MB 0.999
bareinterval/basics/* 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/+ 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/- 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics// 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/abs 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/acos 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/asin 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/atan 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/cos 0.56 k allocs: 0.0423 MB 0.56 k allocs: 0.0423 MB 1
bareinterval/basics/cosh 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/exp 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/inv 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/log 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/sin 0.56 k allocs: 0.0423 MB 0.56 k allocs: 0.0423 MB 1
bareinterval/basics/sinh 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/sqrt 2 allocs: 1.62 kB 2 allocs: 1.62 kB 1
bareinterval/basics/tan 0.29 k allocs: 23 kB 0.29 k allocs: 23 kB 1
bareinterval/basics/tanh 1.03 k allocs: 0.0359 MB 1.03 k allocs: 0.0359 MB 1
interval/basics/* 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/+ 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/- 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics// 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/abs 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/acos 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/asin 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/atan 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/cos 0.561 k allocs: 0.0431 MB 0.561 k allocs: 0.0431 MB 1
interval/basics/cosh 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/exp 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/inv 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/log 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/sin 0.561 k allocs: 0.0431 MB 0.561 k allocs: 0.0431 MB 1
interval/basics/sinh 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/sqrt 3 allocs: 2.45 kB 3 allocs: 2.45 kB 1
interval/basics/tan 0.291 k allocs: 24.4 kB 0.291 k allocs: 24.4 kB 1
interval/basics/tanh 1.03 k allocs: 0.0367 MB 1.03 k allocs: 0.0367 MB 1
time_to_load 0.149 k allocs: 11.2 kB 0.149 k allocs: 11.2 kB 1

@OlivierHnt

Copy link
Copy Markdown
Member

Can't all of this be captured by something in the vein of Base.convert(::Type{BareInterval{T}}, x::ExactReal{T}) where {T} = _unsafe_bareinterval(T, x.value, x.value)?

@timholy

timholy commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Not quite; your approach saves a validation, but

julia> iv1, iv2 = bareinterval(3, 3), bareinterval(3, 4)
([3.0, 3.0], [3.0, 4.0])

julia> @code_lowered iv1*iv2
CodeInfo(
1 ── %1  = IntervalArithmetic.isempty_interval
│    %2  =   dynamic (%1)(x)
└───       goto #4 if not %2
2 ── %4  = x
└───       return %4
3 ──       goto #4
4 ┄─ %7  = IntervalArithmetic.isempty_interval
│    %8  =   dynamic (%7)(y)
└───       goto #7 if not %8
5 ── %10 = y
└───       return %10
6 ──       goto #7
7 ┄─ %13 = IntervalArithmetic.isthinzero
│    %14 =   dynamic (%13)(x)
└───       goto #10 if not %14
8 ── %16 = x
└───       return %16
9 ──       goto #10
10%19 = IntervalArithmetic.isthinzero
│    %20 =   dynamic (%19)(y)
└───       goto #13 if not %20
11%22 = y
└───       return %22
12 ─       goto #13
13%25 = IntervalArithmetic.:&%26 = IntervalArithmetic.isbounded
│    %27 =   dynamic (%26)(x)
│    %28 = IntervalArithmetic.isbounded
│    %29 =   dynamic (%28)(y)
│    %30 =   dynamic (%25)(%27, %29)
└───       goto #16 if not %30
14%32 = IntervalArithmetic._mult
│    %33 = IntervalArithmetic.:*%34 =   dynamic (%32)(%33, x, y)
└───       return %34
15 ─       goto #16
16%37 = IntervalArithmetic._mult
│    %38 = IntervalArithmetic._unbounded_mul
│    %39 =   dynamic (%37)(%38, x, y)
└───       return %39
)

shows a lot of unnecessary work (it's not even showing the four-product min/max), given that a point only needs one signbit and two products. It cuts the time approximately in half, which is a game-changer for my application.

To be clear, it's totally OK if you say "no," I don't want to push you into something you don't want.

@OlivierHnt

Copy link
Copy Markdown
Member

I see. Oh no, I am not opposed in principle, but I always try to fix the root problems (otherwise we end up with too much band-aid...).
I'd say that these specialized functions if we end up having them, they should stay leave in exact.jl since that's where their generic counter parts live.

@timholy

timholy commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

To clarify, you mean move those methods to src/intervals/exact_literals.jl, right?

@OlivierHnt

OlivierHnt commented Aug 6, 2026

Copy link
Copy Markdown
Member

Indeed, sorry. Next to the fallback ones.

An `ExactReal` is a point, so `+`, `-`, `*`, `/` and `\` against a
`BareInterval` of the same number type apply the operation to the two
endpoints directly, rather than promoting the point to a thin interval
and running the interval-interval operator on it.

Each method takes that route only where it is bitwise identical to the
promotion, and delegates the rest: a non-finite point, whose thin
interval is ill-formed; an unbounded interval under `*`, where `0 * Inf`
is flavor dependent; and division by a zero point. Rounding still goes
through `@round`, so the results are unchanged under every rounding
mode. Mixed number types keep the promotion, which is where the point is
rounded to the interval's number type.

The type parameter is bounded by `NumTypes` so that these methods are
more specific than the generic `ExactReal`/`BareInterval` methods, whose
own parameters are bounded by `Real` and `NumTypes`; the tests assert
that dispatch selects them.

Point times interval costs 3.2 ns against the promotion route's 6.4-8.2
ns with rounding `:none`, and 6.7 ns against 9.1-10.2 ns with `:correct`.

Assisted-by: Claude Opus 5 (claude-opus-5) <noreply@anthropic.com>
@timholy

timholy commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Done

@OlivierHnt

OlivierHnt commented Aug 7, 2026

Copy link
Copy Markdown
Member

LGTM on my side. It seems to behave exactly as it does with the previous promotion system; @Kolaru @lbenet thoughts?

EDIT: while we are at it can we also make +(x::Interval{T}, y::ExactReal{T}) etc. benefit from these methods? If it's not trivial, let's not over burden this PR and merge as is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants