FastComplex

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?

class Object
trait Matchable
class Any

Value members

Concrete methods

final
def abs(d: Long): Float
final
def add(a: Long, b: Long): Long
final
def angle(d: Long): Float
final
def apply(real: Float, imag: Float): Long
final
def apply(real: Double, imag: Double): Long
@inline
final
def bits(n: Float): Int
@inline
final
def bits(n: Int): Float
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
@inline
final
def encode(real: Float, imag: Float): Long
@inline
final
def imag(d: Long): Float
final
def isWhole(d: Long): Boolean
final
def multiply(a: Long, b: Long): Long
final
def negate(a: Long): Long
@inline
final
def polar(magnitude: Float, angle: Float): Long
final
def pow(a: Long, b: Long): Long
@inline
final
def real(d: Long): Float
final
def signum(d: Long): Int
final
def subtract(a: Long, b: Long): Long
final
def toRepr(d: Long): String

Concrete fields

final
val i: Long
final
val one: Long
final
val zero: Long