## digitalmars.D.announce - ldexp and frexp benchmark between Mir, C and Phobos

• 9il (54/54) Dec 28 2018 ldexp and frexp are base building blocks for a lot of math
• kinke (8/29) Dec 29 2018 Any chance the multi-precision ldexp can be upstreamed to Phobos
• 9il (3/12) Dec 29 2018 Yes, Mir is Boost licensed, but I don't work on Phobos anymore.
• Iain Buclaw (9/15) Dec 29 2018 You could double the speed of ldexp if you actually used the
• 9il (4/25) Dec 29 2018 Mir has support for LLVM checkedint intrinsics. GDC checkedint
• Guillaume Piolat (4/8) Dec 30 2018 Wow, thanks! Been waiting for an exp() rewrite. And
• kinke (4/7) Dec 31 2018 exp != {ld,fr}exp. Phobos includes a proper single/double
• Guillaume Piolat (8/16) Jan 01 llvm_exp (defers to C runtime) gives considerable speed
• kinke (9/17) Jan 02 My tests back then on Linux also showed new `exp(float)` being
• Guillaume Piolat (4/15) Jan 02 Interesting. At least the VS runtime seems to have different code
9il <ilyayaroshenko gmail.com> writes:
ldexp and frexp are base building blocks for a lot of math
functions.

Here is a small benchmark that compares Mir, C and Phobos
implementations:

https://github.com/libmir/mir-core/blob/master/bench_ldexp_frexp.d

Mir ldexp is 2.5 (5.5 - dmd) times faster for double and float.

=====================
LDC, macos x64:
---------------------------
++++ float ++++
ldexp (Phobos time / Mir time) = 2.55584
ldexp (  stdc time / Mir time) = 0.773019
frexp (Phobos time / Mir time) = 1.04093
frexp (  stdc time / Mir time) = 1.748
---------------------------
++++ double ++++
ldexp (Phobos time / Mir time) = 2.49162
ldexp (  stdc time / Mir time) = 1.31868
frexp (Phobos time / Mir time) = 0.937906
frexp (  stdc time / Mir time) = 1.82241
---------------------------
++++ real ++++
ldexp (Phobos time / Mir time) = 0.999327 (LDC Phobos uses C func
for real)
ldexp (  stdc time / Mir time) = 0.969467 (LDC Mir uses C func
for real)
frexp (Phobos time / Mir time) = 1.02512
frexp (  stdc time / Mir time) = 1.77901

=====================
DMD, macos x64:
---------------------------
++++ float ++++
ldexp (Phobos time / Mir time) = 5.53172
ldexp (  stdc time / Mir time) = 0.535711
frexp (Phobos time / Mir time) = 2.06024
frexp (  stdc time / Mir time) = 0.739571
---------------------------
++++ double ++++
ldexp (Phobos time / Mir time) = 5.32189
ldexp (  stdc time / Mir time) = 0.772949
frexp (Phobos time / Mir time) = 2.02758
frexp (  stdc time / Mir time) = 0.637328
---------------------------
++++ real ++++
ldexp (Phobos time / Mir time) = 2.61905
ldexp (  stdc time / Mir time) = 0.803806
frexp (Phobos time / Mir time) = 1.22398
frexp (  stdc time / Mir time) = 1.08659

Best,
Ilya

This work has been sponsored by Symmetry Investments and Kaleidic
Associates.

http://symmetryinvestments.com/
https://github.com/kaleidicassociates/
Dec 28 2018
kinke <noone nowhere.com> writes:
On Friday, 28 December 2018 at 19:48:28 UTC, 9il wrote:
LDC, macos x64:
---------------------------
++++ float ++++
ldexp (Phobos time / Mir time) = 2.55584
ldexp (  stdc time / Mir time) = 0.773019
frexp (Phobos time / Mir time) = 1.04093
frexp (  stdc time / Mir time) = 1.748
---------------------------
++++ double ++++
ldexp (Phobos time / Mir time) = 2.49162
ldexp (  stdc time / Mir time) = 1.31868
frexp (Phobos time / Mir time) = 0.937906
frexp (  stdc time / Mir time) = 1.82241
---------------------------
++++ real ++++
ldexp (Phobos time / Mir time) = 0.999327 (LDC Phobos uses C
func for real)
ldexp (  stdc time / Mir time) = 0.969467 (LDC Mir uses C func
for real)
frexp (Phobos time / Mir time) = 1.02512
frexp (  stdc time / Mir time) = 1.77901
Any chance the multi-precision ldexp can be upstreamed to Phobos (which currently uses real precision for the float/double overloads, which explains the suboptimal performance)? It'd make a *lot* more sense there, instead of having it in a separate library. It's well-known that there's a lot of remaining std.math functions which need proper single/double precision implementations, and ldexp is one of them.
Dec 29 2018
9il <ilyayaroshenko gmail.com> writes:
On Saturday, 29 December 2018 at 12:35:03 UTC, kinke wrote:
On Friday, 28 December 2018 at 19:48:28 UTC, 9il wrote:
Any chance the multi-precision ldexp can be upstreamed to
Phobos (which currently uses real precision for the
float/double overloads, which explains the suboptimal
performance)? It'd make a *lot* more sense there, instead of
having it in a separate library. It's well-known that there's a
lot of remaining std.math functions which need proper
single/double precision implementations, and ldexp is one of
them.
Yes, Mir is Boost licensed, but I don't work on Phobos anymore. Mir libraries are going to be independent of Phobos.
Dec 29 2018
Iain Buclaw <ibuclaw gdcproject.org> writes:
On Fri, 28 Dec 2018 at 20:50, 9il via Digitalmars-d-announce
<digitalmars-d-announce puremagic.com> wrote:
ldexp and frexp are base building blocks for a lot of math
functions.

Here is a small benchmark that compares Mir, C and Phobos
implementations:

https://github.com/libmir/mir-core/blob/master/bench_ldexp_frexp.d

Mir ldexp is 2.5 (5.5 - dmd) times faster for double and float.
You could double the speed of ldexp if you actually used the checkedint compiler intrinsics rather than implementing it yourself. Using libm's ldexp() is also likely going to be 2-5x slower than using the implementation you've written for mir.ldexp(). For one, your version will be inlined! -- Iain
Dec 29 2018
9il <ilyayaroshenko gmail.com> writes:
On Saturday, 29 December 2018 at 15:15:48 UTC, Iain Buclaw wrote:
On Fri, 28 Dec 2018 at 20:50, 9il via Digitalmars-d-announce
<digitalmars-d-announce puremagic.com> wrote:
ldexp and frexp are base building blocks for a lot of math
functions.

Here is a small benchmark that compares Mir, C and Phobos
implementations:

https://github.com/libmir/mir-core/blob/master/bench_ldexp_frexp.d

Mir ldexp is 2.5 (5.5 - dmd) times faster for double and float.
You could double the speed of ldexp if you actually used the checkedint compiler intrinsics rather than implementing it yourself. Using libm's ldexp() is also likely going to be 2-5x slower than using the implementation you've written for mir.ldexp(). For one, your version will be inlined!
Mir has support for LLVM checkedint intrinsics. GDC checkedint intrinsics are not yet integrated in Mir. https://github.com/libmir/mir-core/blob/master/source/mir/checkedint.d
Dec 29 2018
Guillaume Piolat <first.last gmail.com> writes:
On Friday, 28 December 2018 at 19:48:28 UTC, 9il wrote:
ldexp and frexp are base building blocks for a lot of math
functions.

Here is a small benchmark that compares Mir, C and Phobos
implementations:
Wow, thanks! Been waiting for an exp() rewrite. And Boost-licensed! I'm using expf() from whatever libc is shipped and the variability of results and lack of control is annoying.
Dec 30 2018
kinke <noone nowhere.com> writes:
On Sunday, 30 December 2018 at 13:39:44 UTC, Guillaume Piolat
wrote:
Been waiting for an exp() rewrite. And Boost-licensed! I'm
using expf() from whatever libc is shipped and the variability
of results and lack of control is annoying.
exp != {ld,fr}exp. Phobos includes a proper single/double precision exp implementation since v2.082 and is Boost licensed...
Dec 31 2018
Guillaume Piolat <first.last gmail.com> writes:
On Monday, 31 December 2018 at 13:24:29 UTC, kinke wrote:
On Sunday, 30 December 2018 at 13:39:44 UTC, Guillaume Piolat
wrote:
Been waiting for an exp() rewrite. And Boost-licensed! I'm
using expf() from whatever libc is shipped and the variability
of results and lack of control is annoying.
exp != {ld,fr}exp. Phobos includes a proper single/double precision exp implementation since v2.082 and is Boost licensed...
llvm_exp (defers to C runtime) gives considerable speed improvement over `std.math.exp`. I've tested `expf` form the VS runtime exhaustively for 32-bit `float` and it showed the relative accuracy was within < 0.0002% of std.math.exp, It's not concerning at all, what is more is the variability of C runtime though vs a D function. Looking for speed AND control :)
Jan 01
kinke <noone nowhere.com> writes:
On Tuesday, 1 January 2019 at 23:36:55 UTC, Guillaume Piolat
wrote:
llvm_exp (defers to C runtime) gives considerable speed
improvement over `std.math.exp`.
My tests back then on Linux also showed new `exp(float)` being about half as fast as C, while the double-version was somehow 4x faster.
I've tested `expf` form the VS runtime exhaustively for 32-bit
`float` and it showed the relative accuracy was within <
0.0002% of std.math.exp,

It's not concerning at all, what is more is the variability of
C runtime though vs a D function. Looking for speed AND control
:)
Then look at the implementation of exp() and you'll see that it uses ldexp() once. So by porting Ilya's version (or the Cephes one) to Phobos, I'm sure we can match the C speed for single-precision too.
Jan 02
Guillaume Piolat <first.last gmail.com> writes:
On Wednesday, 2 January 2019 at 09:35:39 UTC, kinke wrote:
On Tuesday, 1 January 2019 at 23:36:55 UTC, Guillaume Piolat
wrote:
llvm_exp (defers to C runtime) gives considerable speed
improvement over `std.math.exp`.
My tests back then on Linux also showed new `exp(float)` being about half as fast as C, while the double-version was somehow 4x faster.
Interesting. At least the VS runtime seems to have different code for `exp(float)` and `exp(double)`. This could be an explanation.
Then look at the implementation of exp() and you'll see that it
uses ldexp() once. So by porting Ilya's version (or the Cephes
one) to Phobos, I'm sure we can match the C speed for
single-precision too.
Good idea.
Jan 02