complex arithmetic in D: multiple questions

J-S Caux js at gmail.com
Fri Mar 9 12:34:40 UTC 2018


Please bear with me, this is a long question!
To explain, I'm a scientist considering switching from C++ to D, 
but before I do, I need to ensure that I can:
- achieve execution speeds comparable to C++ (for the same 
accuracy; I can accept a slight slowdown, call it 30%, to get a 
few more digits (which I typically don't need))
- easily perform all standard mathematical operations on complex 
numbers
- (many other things not relevant here: memory use, 
parallelization, etc).

In the two files linked below, I compare execution speed/accuracy 
between D and C++ when using log on complex variables:

https://www.dropbox.com/s/hfw7nkwg25mk37u/test_cx.d?dl=0
https://www.dropbox.com/s/hfw7nkwg25mk37u/test_cx.d?dl=0

The idea is simple: let a complex variable be uniformly 
distributed around the unit circle. Summing the logs should give 
zero.

In the D code, I've defined an "own" version of the log, log_cx, 
since std.complex (tragically!) does not provide this function 
(and many others, see recent threads 
https://forum.dlang.org/post/dewzhtnpqkaqkzxwpkrs@forum.dlang.org 
and 
https://forum.dlang.org/thread/lsnuevdefktulxltoqpj@forum.dlang.org, and issue https://issues.dlang.org/show_bug.cgi?id=18571).

First, speed/accuracy (times for 1M points in all cases):
D:
dmd, no flags:
Complex!real: re, im (should be 0): 
-9.24759400999786151942e-15	6.26324079407839123978e-14
time for 1000000 pts: 190 ms, 508 μs, and 9 hnsecs
Complex!double: re, im (should be 0): 
-1.96986871259241524967e-12	5.46260919029144254022e-09
time for 1000000 pts: 455 ms, 888 μs, and 7 hnsecs

dmd -release -inline -O:
Complex!real: re, im (should be 0): 
-9.24759400999786151942e-15	6.26324079407839123978e-14
time for 1000000 pts: 175 ms, 352 μs, and 3 hnsecs
Complex!double: re, im (should be 0): 
-4.23880765557105362133e-14	5.46260919029144254022e-09
time for 1000000 pts: 402 ms, 965 μs, and 7 hnsecs

ldc2, no flags:
Complex!real: re, im (should be 0): 
-9.24759400999786151942e-15	6.26324079407839123978e-14
time for 1000000 pts: 184 ms, 353 μs, and 9 hnsecs
Complex!double: re, im (should be 0): 
-1.96986871259241524967e-12	5.46260919029144254022e-09
time for 1000000 pts: 436 ms, 526 μs, and 8 hnsecs

ldc2 -release -O:
Complex!real: re, im (should be 0): 
-9.24759400999786151942e-15	6.26324079407839123978e-14
time for 1000000 pts: 108 ms and 966 μs
Complex!double: re, im (should be 0): 
-1.96986871259241524967e-12	5.46260919029144254022e-09
time for 1000000 pts: 330 ms, 421 μs, and 8 hnsecs

As expected accuracy with Complex!real is about 4 digits better, 
and the best combo is ldc2 with flags.

Now C++:
GCC 7.1.0, -O3:
complex<double>: re, im (should be 0): 
(8.788326118779445e-13,1.433519814600731e-11)
time for 1000000 pts: 0.042751 seconds.

Apple LLVM version 9.0.0 (clang-900.0.39.2), -O3:
complex<double>: re, im (should be 0): 
(-3.0160318686967e-12,1.433519814600731e-11)
time for 1000000 pts: 0.038715 seconds.

So simple C++ is thrice as fast as the best-achieved D I managed.

Now for my questions:
- I would expect the D `Complex!double` case to work faster than 
the `real` one. Why is it the other way around? [I can accept 
(and use) D with Complex!real running 1/3 the speed of C++ (but 
with increased accuracy), but I'd also love to be able to run D 
with `Complex!double` at C++ speeds, since the tradeoff might be 
worth it for some calculations]
- what is the best way to correct the unfortunate (to be polite) 
omission of many standard mathematical functions from 
std.complex? [if I may be frank, this is a real pain for us 
scientists] There exists 
https://gist.github.com/Biotronic/17af645c2c9b7913de1f04980cd22b37 but can this be integrated (after improvements) in the language, or should I (re)build my own?
- for my education, why was the decision made to go from the 
built-in types `creal` etc to the `Complex` type?

[related questions:


More information about the Digitalmars-d-learn mailing list