object
FastComplex
Value Members
-
final
def
!=(arg0: Any): Boolean
-
final
def
##(): Int
-
final
def
==(arg0: Any): Boolean
-
final
def
abs(d: Long): Float
-
final
def
add(a: Long, b: Long): Long
-
final
def
angle(d: Long): Float
-
final
def
apply(real: Double, imag: Double): Long
-
final
def
apply(real: Float, imag: Float): Long
-
final
def
asInstanceOf[T0]: T0
-
final
def
bits(n: Int): Float
-
final
def
bits(n: Float): Int
-
def
clone(): AnyRef
-
final
def
complexSignum(d: Long): Long
-
final
def
conjugate(d: Long): Long
-
final
def
decode(d: Long): (Float, Float)
-
final
def
divide(a: Long, b: Long): Long
-
final
def
encode(real: Float, imag: Float): Long
-
final
def
eq(arg0: AnyRef): Boolean
-
def
equals(arg0: Any): Boolean
-
def
finalize(): Unit
-
final
def
getClass(): Class[_]
-
def
hashCode(): Int
-
final
val
i: Long
-
final
def
imag(d: Long): Float
-
final
def
isInstanceOf[T0]: Boolean
-
final
def
isWhole(d: Long): Boolean
-
final
def
multiply(a: Long, b: Long): Long
-
final
def
ne(arg0: AnyRef): Boolean
-
final
def
negate(a: Long): Long
-
final
def
notify(): Unit
-
final
def
notifyAll(): Unit
-
final
val
one: Long
-
final
def
polar(magnitude: Float, angle: Float): Long
-
final
def
pow(a: Long, b: Long): Long
-
final
def
real(d: Long): Float
-
final
def
signum(d: Long): Int
-
final
def
subtract(a: Long, b: Long): Long
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
-
final
def
toRepr(d: Long): String
-
def
toString(): String
-
final
def
wait(): Unit
-
final
def
wait(arg0: Long, arg1: Int): Unit
-
final
def
wait(arg0: Long): Unit
-
final
val
zero: Long
Inherited from AnyRef
Inherited from Any
FastComplex is an ugly, beautiful hack.
The basic idea is to encode two 32-bit Floats into a single 64-bit Long. The lower-32 bits are the "real" Float and the upper-32 are the "imaginary" Float.
Since we're overloading the meaning of Long, all the operations have to be defined on the FastComplex object, meaning the syntax for using this is a bit ugly. To add to the ugly beauty of the whole thing I could imagine defining implicit operators on Long like +@, -@, *@, /@, etc.
You might wonder why it's even worth doing this. The answer is that when you need to allocate an array of e.g. 10-20 million complex numbers, the GC overhead of using *any* object is HUGE. Since we can't build our own "pass-by-value" types on the JVM we are stuck doing an encoding like this.
Here are some profiling numbers for summing an array of complex numbers, timed against a concrete case class implementation using Float (in ms):
size | encoded | class 1M | 5.1 | 5.8 5M | 28.5 | 91.7 10M | 67.7 | 828.1 20M | 228.0 | 2687.0
Not bad, eh?