
Rational rendering and floating bar - andyonthewings
http://iquilezles.org/www/articles/floatingbar/floatingbar.htm
======
theoh
There are rational geometry libraries which are precise (edit: I mean that
answers are "exact"): [http://www.algorithmic-
solutions.info/leda_guide/Geometry.ht...](http://www.algorithmic-
solutions.info/leda_guide/Geometry.html)

Quilez's concern with how the number fits into 32 or 64 bits _may_ be
necessary for performance, but using arbitrary precision numerators and
denominators is the only way to achieve the robustness he was initially
pursuing.

------
nimish
I was hoping the author went full circle to reinventing floating point, but
this is a great writeup of the process. Really good motivation.

~~~
tomxor
Re-inventing floating point format would be missing the point (edit: i
honestly did not see that pun sorry).. floating point formats cannot represent
all of the rational numbers that a fraction could using the equivalent bits
e.g 1/10 can be represented in base 10 decimals but not in base 2 float (where
it has a repeating significand much like 1/3 in base 10), which becomes a
problem when doing further math on it, try: 1/10 + 2/10).

Both methods result in "holes" bellow zero (necessarily of course), but they
do not fit inside each other. However within a limited set of operations,
rational numbers (within a capable format, and with necessary operators) have
some interesting properties over floating point math that makes them
desirable, i.e not loosing precision (unless overflow due to encountering
large primes), and they are less expensive (built on integer math).

What he did do, is make a rational number bit format (floating bar) which
stores everything as fractions, it's quite elegant really and anyone familiar
with IEEE754 will see the similarities.

~~~
Veedrac
Floating point is also built on integer math, and cheaper operations at that.

~~~
tomxor
Ultimately yes, but I'd be interested in a side by side comparison, without
FPUs. Also as explained in the article, divide (which is expensive float
operation) is as cheap as integer multiplies with fractions.

~~~
Veedrac
It's very rare not to need GCD reduction, though; multiplying values burns
through bits extremely fast. Only doing factor-2 reduction isn't infeasible
but you'd be further damaging an already iffy type.

~~~
tomxor
> It's very rare not to need GCD reduction, though

Yes good point, I did wonder this... it's easy to look at the individual
operations and think "that's cheap" but holistically, the GCD which I assume
is expensive could make the overall performance benefits moot. It might be
optimisable to not do it unnecessarily after _every_ operation though?

Perhaps then the only advantage in terms of hardware use is that it can be
implemented on a CPU with only ints e.g small micro-controllers with no FPU or
int divide. I think that by comparison implementing a soft FPU would be
impractical, still niche I guess.

~~~
Veedrac
I'm not sure, but I suspect your best alternative to 32-bit floats/floating-
bar-rationals or 64-bit rationals when you have no FPU is a 64-bit fixed-point
value with compressed floating-point representations if you need to store it
compactly in memory.

------
twic
> Exceptions to the rule of "operations on rational number produce rational
> numbers" are the square roots and the trigonometric/transcendental
> functions. For the later, I always express my opinion that if you find
> yourself doing trigonometry in the geometrical internals of your renderer,
> you are most probably doing things wrong

Is that because you can express a rotation (etc) as a matrix? If so, don't you
need to be able to do the trigonometry exactly to create a correct rational
matrix in the first place? What am i missing?

Or is it that you just don't need to do those sorts of operations at all
inside the renderer?

~~~
jmts
I assume (though I'm certainly not as knowledgeable as Inigo) that he's
suggesting most functionality that uses trigonometry during rendering in some
way tends to be performed using dot- and cross-products - which are calculated
using only basic arithmetic operations - and therefore don't require slow
mathematical function calls. If the actual value of a cosine is needed in some
way, it will likely be calculated via the dot-product of two vectors, where
one or both has unit length.

As far as construction of rotation matrices goes, most of that will be baked
before rendering a frame, so expensive trigonometric calculations and their
conversion to rationals will occur ahead of time and therefore much less
frequently than anything done per pixel, improving performance.

In computer graphics, because a great many calculations need to be done for
each pixel to be displayed, use of expensive functions tends to be avoided. In
the literature I recall reading a number of triangle-ray intersection
algorithms where each breaks down precisely how many adds, multiplies,
divisions, etc are performed because the goal is to minimize all these things.
If you are intersecting 10 triangles per pixel at 2 million pixels per frame,
a single multiply per intersection becomes 20 million multiplies per frame. By
contrast, recalculating the camera matrix using expensive functions should
only happen once per frame.

~~~
jacobolus
Everyone should use vector methods and shy away from transcendental functions
to the extent possible.

It is usually (but not always) possible to reframe problems in such a way that
exponentials (including sine/cosine/tangent) and logarithms (including
arcsine, arctangent, ..) are unnecessary.

Vector methods are much faster, have fewer weird edge cases, are less subject
to rounding error, etc.

As an example: if you want to store a planar vector, use a pair of coordinates
instead of an angle measure and magnitude. If you want to store an 2d
orientation or rotation, still use a pair of (x, y) coordinates on the unit
circle instead of angle measure (which is a logarithmic quantity). If you want
to reduce your pair of coordinates to a single number, use the stereographic
projection, which only requires division.

~~~
westoncb
Would you mind expanding on the idea that an angle measure is a logarithmic
quantity and that sin/cos/tan are exponentials (or providing a phrase I could
google)? I've never come across a formulation/characterization like that, and
it sounds useful...

~~~
jacobolus
You can break the exponential function into the part acting on a scalar and
the part acting on a bivector, and then furthermore break those into even and
odd parts:

exp(ρ + θi) = (cosh ρ + sinh ρ)(cos θ + i sin θ)

The angle measure in the above is the θ part. The “linear space” expression of
the orientation/rotation is a 2-dimensional quanitity cos θ + i sin θ.

Or if you start with the 2-coordinate version x + iy, where x^2 + y^2 = 1, you
can find the angle measure by taking the natural logarithm, imag(log(x + yi)).

Rotations are naturally a multiplicative concept. If you have a rotation a +
bi and a rotation c + di, then you can compose them like (a + bi)(c + di) =
(ac - bd) + (ad + bc)i (you might recognize this as the the “angle sum”
identities from high school trigonometry class).

The idea of the logarithm is that you can convert a multiplicative structure
into an additive one. So if you have rotations Q and R, you could normally
compose them like QR, but as an alternative you can use a log-space
representation (angle measure): QR = exp(log(Q) + log(R)).

A rotation inherently comes with an orientation. The i (“imaginary unit”) is
in my opinion properly thought of as a bivector, oriented like a plane. When
we express something as a scalar-valued angle measure, we have stripped the
orientation out.

~~~
twic
Thanks for this - i have studied very little maths, so even this perhaps quite
basic stuff is like magic for me!

I love the revelation that log/exp shifts between Cartesian and (log-)polar
meanings of complex numbers. That's enormously satisfying for some reason.

I note that the pattern in multiplying rotations also comes up if you do it
with matrices:

    
    
        a -b     c -d     ac-bd -(ad+bc)
        b  a  .  d  c  =  ad+bc    ac-bd
    

Does something similar happen with quaternions / geometric products in 3D?

~~~
jacobolus
Taking 3D rotations into log space gets tricky. 3D rotation is not
commutative, so if you have two quaternions Q and R, you can’t in general say
that QR = exp(log(Q))exp(log(R)) = exp(log(Q) + log(R)). That identity only
holds if the bivector (“imaginary”) parts of Q and R are oriented the same way
in space, i.e. are scalar multiples of each-other. Otherwise in general
exp(log(Q))exp(log(R)) ≠ exp(log(R))exp(log(Q)).

The log space version is still useful though if you want to e.g. take the nth
root of a spatial rotation.

------
Flow
Very cool article but the scroll-jacking makes this painful to read on an
iPhone. :-(

~~~
sbr464
Enabling reader mode in safari fixes.

~~~
Flow
I get no Reader Mode icon for this site in mobile Safari, only on desktop
Safari. :-(

~~~
ssvss
I get reader mode in iPad, so the problem may be because of iPhone form
factor, not mobile safari.

------
erikpukinskis
Inigo is a pioneer living decades ahead of the field. Utterly futuristic
approach to graphics.

