
(FPCore (a b eps) :precision binary64 (/ (* eps (- (exp (* (+ a b) eps)) 1.0)) (* (- (exp (* a eps)) 1.0) (- (exp (* b eps)) 1.0))))
double code(double a, double b, double eps) {
return (eps * (exp(((a + b) * eps)) - 1.0)) / ((exp((a * eps)) - 1.0) * (exp((b * eps)) - 1.0));
}
real(8) function code(a, b, eps)
real(8), intent (in) :: a
real(8), intent (in) :: b
real(8), intent (in) :: eps
code = (eps * (exp(((a + b) * eps)) - 1.0d0)) / ((exp((a * eps)) - 1.0d0) * (exp((b * eps)) - 1.0d0))
end function
public static double code(double a, double b, double eps) {
return (eps * (Math.exp(((a + b) * eps)) - 1.0)) / ((Math.exp((a * eps)) - 1.0) * (Math.exp((b * eps)) - 1.0));
}
def code(a, b, eps): return (eps * (math.exp(((a + b) * eps)) - 1.0)) / ((math.exp((a * eps)) - 1.0) * (math.exp((b * eps)) - 1.0))
function code(a, b, eps) return Float64(Float64(eps * Float64(exp(Float64(Float64(a + b) * eps)) - 1.0)) / Float64(Float64(exp(Float64(a * eps)) - 1.0) * Float64(exp(Float64(b * eps)) - 1.0))) end
function tmp = code(a, b, eps) tmp = (eps * (exp(((a + b) * eps)) - 1.0)) / ((exp((a * eps)) - 1.0) * (exp((b * eps)) - 1.0)); end
code[a_, b_, eps_] := N[(N[(eps * N[(N[Exp[N[(N[(a + b), $MachinePrecision] * eps), $MachinePrecision]], $MachinePrecision] - 1.0), $MachinePrecision]), $MachinePrecision] / N[(N[(N[Exp[N[(a * eps), $MachinePrecision]], $MachinePrecision] - 1.0), $MachinePrecision] * N[(N[Exp[N[(b * eps), $MachinePrecision]], $MachinePrecision] - 1.0), $MachinePrecision]), $MachinePrecision]), $MachinePrecision]
\begin{array}{l}
\\
\frac{\varepsilon \cdot \left(e^{\left(a + b\right) \cdot \varepsilon} - 1\right)}{\left(e^{a \cdot \varepsilon} - 1\right) \cdot \left(e^{b \cdot \varepsilon} - 1\right)}
\end{array}
Sampling outcomes in binary64 precision:
Herbie found 4 alternatives:
| Alternative | Accuracy | Speedup |
|---|
(FPCore (a b eps) :precision binary64 (/ (* eps (- (exp (* (+ a b) eps)) 1.0)) (* (- (exp (* a eps)) 1.0) (- (exp (* b eps)) 1.0))))
double code(double a, double b, double eps) {
return (eps * (exp(((a + b) * eps)) - 1.0)) / ((exp((a * eps)) - 1.0) * (exp((b * eps)) - 1.0));
}
real(8) function code(a, b, eps)
real(8), intent (in) :: a
real(8), intent (in) :: b
real(8), intent (in) :: eps
code = (eps * (exp(((a + b) * eps)) - 1.0d0)) / ((exp((a * eps)) - 1.0d0) * (exp((b * eps)) - 1.0d0))
end function
public static double code(double a, double b, double eps) {
return (eps * (Math.exp(((a + b) * eps)) - 1.0)) / ((Math.exp((a * eps)) - 1.0) * (Math.exp((b * eps)) - 1.0));
}
def code(a, b, eps): return (eps * (math.exp(((a + b) * eps)) - 1.0)) / ((math.exp((a * eps)) - 1.0) * (math.exp((b * eps)) - 1.0))
function code(a, b, eps) return Float64(Float64(eps * Float64(exp(Float64(Float64(a + b) * eps)) - 1.0)) / Float64(Float64(exp(Float64(a * eps)) - 1.0) * Float64(exp(Float64(b * eps)) - 1.0))) end
function tmp = code(a, b, eps) tmp = (eps * (exp(((a + b) * eps)) - 1.0)) / ((exp((a * eps)) - 1.0) * (exp((b * eps)) - 1.0)); end
code[a_, b_, eps_] := N[(N[(eps * N[(N[Exp[N[(N[(a + b), $MachinePrecision] * eps), $MachinePrecision]], $MachinePrecision] - 1.0), $MachinePrecision]), $MachinePrecision] / N[(N[(N[Exp[N[(a * eps), $MachinePrecision]], $MachinePrecision] - 1.0), $MachinePrecision] * N[(N[Exp[N[(b * eps), $MachinePrecision]], $MachinePrecision] - 1.0), $MachinePrecision]), $MachinePrecision]), $MachinePrecision]
\begin{array}{l}
\\
\frac{\varepsilon \cdot \left(e^{\left(a + b\right) \cdot \varepsilon} - 1\right)}{\left(e^{a \cdot \varepsilon} - 1\right) \cdot \left(e^{b \cdot \varepsilon} - 1\right)}
\end{array}
NOTE: a and b should be sorted in increasing order before calling this function.
(FPCore (a b eps)
:precision binary64
(if (<= eps 8.8e-90)
(-
(+
(+
(* eps 0.5)
(fma
a
(+ (* (* eps eps) 0.3333333333333333) (* -0.5 (* eps (* eps 0.5))))
(/ 1.0 a)))
(/ 1.0 b))
(* eps 0.5))
(*
(/ eps (expm1 (* eps a)))
(/ (expm1 (* eps (+ a b))) (expm1 (* eps b))))))assert(a < b);
double code(double a, double b, double eps) {
double tmp;
if (eps <= 8.8e-90) {
tmp = (((eps * 0.5) + fma(a, (((eps * eps) * 0.3333333333333333) + (-0.5 * (eps * (eps * 0.5)))), (1.0 / a))) + (1.0 / b)) - (eps * 0.5);
} else {
tmp = (eps / expm1((eps * a))) * (expm1((eps * (a + b))) / expm1((eps * b)));
}
return tmp;
}
a, b = sort([a, b]) function code(a, b, eps) tmp = 0.0 if (eps <= 8.8e-90) tmp = Float64(Float64(Float64(Float64(eps * 0.5) + fma(a, Float64(Float64(Float64(eps * eps) * 0.3333333333333333) + Float64(-0.5 * Float64(eps * Float64(eps * 0.5)))), Float64(1.0 / a))) + Float64(1.0 / b)) - Float64(eps * 0.5)); else tmp = Float64(Float64(eps / expm1(Float64(eps * a))) * Float64(expm1(Float64(eps * Float64(a + b))) / expm1(Float64(eps * b)))); end return tmp end
NOTE: a and b should be sorted in increasing order before calling this function. code[a_, b_, eps_] := If[LessEqual[eps, 8.8e-90], N[(N[(N[(N[(eps * 0.5), $MachinePrecision] + N[(a * N[(N[(N[(eps * eps), $MachinePrecision] * 0.3333333333333333), $MachinePrecision] + N[(-0.5 * N[(eps * N[(eps * 0.5), $MachinePrecision]), $MachinePrecision]), $MachinePrecision]), $MachinePrecision] + N[(1.0 / a), $MachinePrecision]), $MachinePrecision]), $MachinePrecision] + N[(1.0 / b), $MachinePrecision]), $MachinePrecision] - N[(eps * 0.5), $MachinePrecision]), $MachinePrecision], N[(N[(eps / N[(Exp[N[(eps * a), $MachinePrecision]] - 1), $MachinePrecision]), $MachinePrecision] * N[(N[(Exp[N[(eps * N[(a + b), $MachinePrecision]), $MachinePrecision]] - 1), $MachinePrecision] / N[(Exp[N[(eps * b), $MachinePrecision]] - 1), $MachinePrecision]), $MachinePrecision]), $MachinePrecision]]
\begin{array}{l}
[a, b] = \mathsf{sort}([a, b])\\
\\
\begin{array}{l}
\mathbf{if}\;\varepsilon \leq 8.8 \cdot 10^{-90}:\\
\;\;\;\;\left(\left(\varepsilon \cdot 0.5 + \mathsf{fma}\left(a, \left(\varepsilon \cdot \varepsilon\right) \cdot 0.3333333333333333 + -0.5 \cdot \left(\varepsilon \cdot \left(\varepsilon \cdot 0.5\right)\right), \frac{1}{a}\right)\right) + \frac{1}{b}\right) - \varepsilon \cdot 0.5\\
\mathbf{else}:\\
\;\;\;\;\frac{\varepsilon}{\mathsf{expm1}\left(\varepsilon \cdot a\right)} \cdot \frac{\mathsf{expm1}\left(\varepsilon \cdot \left(a + b\right)\right)}{\mathsf{expm1}\left(\varepsilon \cdot b\right)}\\
\end{array}
\end{array}
if eps < 8.79999999999999943e-90Initial program 2.2%
associate-*l/2.2%
*-commutative2.2%
expm1-def3.8%
*-commutative3.8%
expm1-def10.0%
*-commutative10.0%
expm1-def33.9%
*-commutative33.9%
Simplified33.9%
Taylor expanded in b around 0 14.1%
Taylor expanded in a around 0 98.4%
+-commutative98.4%
associate--l+98.4%
Simplified98.4%
if 8.79999999999999943e-90 < eps Initial program 18.4%
times-frac18.4%
expm1-def56.9%
*-commutative56.9%
expm1-def56.3%
*-commutative56.3%
expm1-def97.5%
*-commutative97.5%
Simplified97.5%
Final simplification98.3%
NOTE: a and b should be sorted in increasing order before calling this function. (FPCore (a b eps) :precision binary64 (+ (/ 1.0 a) (/ 1.0 b)))
assert(a < b);
double code(double a, double b, double eps) {
return (1.0 / a) + (1.0 / b);
}
NOTE: a and b should be sorted in increasing order before calling this function.
real(8) function code(a, b, eps)
real(8), intent (in) :: a
real(8), intent (in) :: b
real(8), intent (in) :: eps
code = (1.0d0 / a) + (1.0d0 / b)
end function
assert a < b;
public static double code(double a, double b, double eps) {
return (1.0 / a) + (1.0 / b);
}
[a, b] = sort([a, b]) def code(a, b, eps): return (1.0 / a) + (1.0 / b)
a, b = sort([a, b]) function code(a, b, eps) return Float64(Float64(1.0 / a) + Float64(1.0 / b)) end
a, b = num2cell(sort([a, b])){:}
function tmp = code(a, b, eps)
tmp = (1.0 / a) + (1.0 / b);
end
NOTE: a and b should be sorted in increasing order before calling this function. code[a_, b_, eps_] := N[(N[(1.0 / a), $MachinePrecision] + N[(1.0 / b), $MachinePrecision]), $MachinePrecision]
\begin{array}{l}
[a, b] = \mathsf{sort}([a, b])\\
\\
\frac{1}{a} + \frac{1}{b}
\end{array}
Initial program 4.1%
associate-*l/4.1%
*-commutative4.1%
expm1-def5.6%
*-commutative5.6%
expm1-def15.4%
*-commutative15.4%
expm1-def39.1%
*-commutative39.1%
Simplified39.1%
Taylor expanded in eps around 0 78.4%
Taylor expanded in a around 0 96.8%
Final simplification96.8%
NOTE: a and b should be sorted in increasing order before calling this function. (FPCore (a b eps) :precision binary64 (if (<= a -2e-107) (/ 1.0 b) (/ 1.0 a)))
assert(a < b);
double code(double a, double b, double eps) {
double tmp;
if (a <= -2e-107) {
tmp = 1.0 / b;
} else {
tmp = 1.0 / a;
}
return tmp;
}
NOTE: a and b should be sorted in increasing order before calling this function.
real(8) function code(a, b, eps)
real(8), intent (in) :: a
real(8), intent (in) :: b
real(8), intent (in) :: eps
real(8) :: tmp
if (a <= (-2d-107)) then
tmp = 1.0d0 / b
else
tmp = 1.0d0 / a
end if
code = tmp
end function
assert a < b;
public static double code(double a, double b, double eps) {
double tmp;
if (a <= -2e-107) {
tmp = 1.0 / b;
} else {
tmp = 1.0 / a;
}
return tmp;
}
[a, b] = sort([a, b]) def code(a, b, eps): tmp = 0 if a <= -2e-107: tmp = 1.0 / b else: tmp = 1.0 / a return tmp
a, b = sort([a, b]) function code(a, b, eps) tmp = 0.0 if (a <= -2e-107) tmp = Float64(1.0 / b); else tmp = Float64(1.0 / a); end return tmp end
a, b = num2cell(sort([a, b])){:}
function tmp_2 = code(a, b, eps)
tmp = 0.0;
if (a <= -2e-107)
tmp = 1.0 / b;
else
tmp = 1.0 / a;
end
tmp_2 = tmp;
end
NOTE: a and b should be sorted in increasing order before calling this function. code[a_, b_, eps_] := If[LessEqual[a, -2e-107], N[(1.0 / b), $MachinePrecision], N[(1.0 / a), $MachinePrecision]]
\begin{array}{l}
[a, b] = \mathsf{sort}([a, b])\\
\\
\begin{array}{l}
\mathbf{if}\;a \leq -2 \cdot 10^{-107}:\\
\;\;\;\;\frac{1}{b}\\
\mathbf{else}:\\
\;\;\;\;\frac{1}{a}\\
\end{array}
\end{array}
if a < -2e-107Initial program 7.3%
associate-*l/7.3%
*-commutative7.3%
expm1-def8.6%
*-commutative8.6%
expm1-def14.1%
*-commutative14.1%
expm1-def53.5%
*-commutative53.5%
Simplified53.5%
Taylor expanded in b around 0 73.4%
if -2e-107 < a Initial program 2.8%
associate-*l/2.8%
*-commutative2.8%
expm1-def4.3%
*-commutative4.3%
expm1-def16.0%
*-commutative16.0%
expm1-def33.2%
*-commutative33.2%
Simplified33.2%
Taylor expanded in a around 0 58.0%
Final simplification62.4%
NOTE: a and b should be sorted in increasing order before calling this function. (FPCore (a b eps) :precision binary64 (/ 1.0 a))
assert(a < b);
double code(double a, double b, double eps) {
return 1.0 / a;
}
NOTE: a and b should be sorted in increasing order before calling this function.
real(8) function code(a, b, eps)
real(8), intent (in) :: a
real(8), intent (in) :: b
real(8), intent (in) :: eps
code = 1.0d0 / a
end function
assert a < b;
public static double code(double a, double b, double eps) {
return 1.0 / a;
}
[a, b] = sort([a, b]) def code(a, b, eps): return 1.0 / a
a, b = sort([a, b]) function code(a, b, eps) return Float64(1.0 / a) end
a, b = num2cell(sort([a, b])){:}
function tmp = code(a, b, eps)
tmp = 1.0 / a;
end
NOTE: a and b should be sorted in increasing order before calling this function. code[a_, b_, eps_] := N[(1.0 / a), $MachinePrecision]
\begin{array}{l}
[a, b] = \mathsf{sort}([a, b])\\
\\
\frac{1}{a}
\end{array}
Initial program 4.1%
associate-*l/4.1%
*-commutative4.1%
expm1-def5.6%
*-commutative5.6%
expm1-def15.4%
*-commutative15.4%
expm1-def39.1%
*-commutative39.1%
Simplified39.1%
Taylor expanded in a around 0 47.7%
Final simplification47.7%
(FPCore (a b eps) :precision binary64 (/ (+ a b) (* a b)))
double code(double a, double b, double eps) {
return (a + b) / (a * b);
}
real(8) function code(a, b, eps)
real(8), intent (in) :: a
real(8), intent (in) :: b
real(8), intent (in) :: eps
code = (a + b) / (a * b)
end function
public static double code(double a, double b, double eps) {
return (a + b) / (a * b);
}
def code(a, b, eps): return (a + b) / (a * b)
function code(a, b, eps) return Float64(Float64(a + b) / Float64(a * b)) end
function tmp = code(a, b, eps) tmp = (a + b) / (a * b); end
code[a_, b_, eps_] := N[(N[(a + b), $MachinePrecision] / N[(a * b), $MachinePrecision]), $MachinePrecision]
\begin{array}{l}
\\
\frac{a + b}{a \cdot b}
\end{array}
herbie shell --seed 2023221
(FPCore (a b eps)
:name "expq3 (problem 3.4.2)"
:precision binary64
:pre (and (< -1.0 eps) (< eps 1.0))
:herbie-target
(/ (+ a b) (* a b))
(/ (* eps (- (exp (* (+ a b) eps)) 1.0)) (* (- (exp (* a eps)) 1.0) (- (exp (* b eps)) 1.0))))