Live data from Hacker News

Even faster asin() was staring right at me

16bpp.net

11–20 of 68 posts

Re: Even faster asin() was staring right at me

#11
post #3

Earlier quoted context omitted.

On modern machines, looking things up can be slower than recomputing it, when the computation is simple. This is because the memory is much slower than the CPU, which means you can often compute something many times over before the answer from memory arrives.

It may be, especially when it comes to unnecessary cache. But I think `atan` is almost a brute force. Lookup is nothing comparing to that. Sin/cos must be borders of sqrt(x²+y²). It is also cached indeed.

What do you mean brute force?

We can compute these things using iteration or polynomial approximations (sufficient for 64 bit).

Re: Even faster asin() was staring right at me

#12
post #3

I think it is `atan` function. Sin is almost a lookup query.

On modern machines, looking things up can be slower than recomputing it, when the computation is simple. This is because the memory is much slower than the CPU, which means you can often compute something many times over before the answer from memory arrives.

Interesting. About 20 years ago, it must have been the other way around because I remember this paper [1] where the authors were able to speed up the log function by making use of a lookup table in the CPU cache.

[1] https://www.researchgate.net/profile/Nikki-Mirghafori/public...

Re: Even faster asin() was staring right at me

#13
post #3

I think it is `atan` function. Sin is almost a lookup query.

On modern machines, looking things up can be slower than recomputing it, when the computation is simple. This is because the memory is much slower than the CPU, which means you can often compute something many times over before the answer from memory arrives.

Unless your lookup table is small enough to only use a portion of your L1 cache and you're calling it so much that the lookup table is never evicted :)

Re: Even faster asin() was staring right at me

#14
post #12
post #3

Earlier quoted context omitted.

On modern machines, looking things up can be slower than recomputing it, when the computation is simple. This is because the memory is much slower than the CPU, which means you can often compute something many times over before the answer from memory arrives.

Interesting. About 20 years ago, it must have been the other way around because I remember this paper [1] where the authors were able to speed up the log function by making use of a lookup table in the CPU cache. [1] https://www.researchgate.net/profile/Nikki-Mirghafori/public...

It’s a delicate balance and really hard to benchmark. You can write a micro benchmark that keeps the lookup table in cache but what if your function isn’t the only thing being done in a loop? Then even if it’s in the hotpath, there’s insufficient cache to keep the table loaded the entire way through the loop and lookup is slower.

TLDR: it depends on the usage and we actually should have multiple functions that are specialized based on the properties of the caller’s needs where the caller can try a cache or compute approach.

Re: Even faster asin() was staring right at me

#15
Cool, although more ILP (instruction-level parallelism) might not necessarily be better on a modern GPU, which doesn't have much ILP, if any (instead it uses those resources to execute several threads in parallel).

That might explain why the original Cg (a GPU programming language) code did not use Estrin's, since at least the code in the post does add 1 extra op (squaring `abs_x`).

(AMD GPUs used to use VLIW (very long instruction word) which is "static" ILP).

Re: Even faster asin() was staring right at me

#16
post #10

Did you try polynomial preprocessing methods, like Knuth's and Estrin's methods? https://en.wikipedia.org/wiki/Polynomial_evaluation#Evaluati... they let you compute polynomials with half the multiplications of Horner's method, and I used them in the past to improve the speed of the exponential function in Boost.

yes, Estrin's method is the update

Sorry, I said that wrong. Estrin's doesn't reduce the number of multiplications.

Re: Even faster asin() was staring right at me

#18
post #12
post #3

Earlier quoted context omitted.

On modern machines, looking things up can be slower than recomputing it, when the computation is simple. This is because the memory is much slower than the CPU, which means you can often compute something many times over before the answer from memory arrives.

Interesting. About 20 years ago, it must have been the other way around because I remember this paper [1] where the authors were able to speed up the log function by making use of a lookup table in the CPU cache. [1] https://www.researchgate.net/profile/Nikki-Mirghafori/public...

It........depends.

I make things faster all the time by leveraging various CPU caches, sometimes even disk or networked disks. As a general principle though, memory lookups are substantially slower than CPU (and that has indeed changed over time; a decade or three ago they were close to equal), and even cache lookups are fairly comparatively slow, especially when you consider whole-program optimization.

That isn't to say that you can't speed things up with caches, but that you have to be replacing a lot of computations for even very small caches to be practically better (and even very small caches aren't helpful if the whole-program workload is such that you'll have to pull those caches from main RAM each time you use them).

To your paper in particular, their technique still assumes reasonably small caches which you constantly access (so that you never have to reach out to main RAM), even when it was written, and part of what makes it faster is that it's nowhere near as accurate as 1ULP.

Logarithms are interesting because especially across their entire domain they can take 40-120 cycles to compute, more if you're not very careful with the implementation. Modern computers have fairly fast floating-point division and fused multiply-add, so something I often do nowadays is represent them as a ratio of two quadratics (usually rescaling the other math around the problem to avoid the leading coefficient on one of those quadratics) to achieve bounded error in my domain of interest. It's much faster than a LUT (especially when embedded in a larger computation and not easily otherwise parallelizable) and much faster than full-precision solutions. It's also pretty trivially vectorizable in case your problem is amenable to small batches. Other characteristics of your problem might cause you to favor other solutions.

Re: Even faster asin() was staring right at me

#19

I haven't kept up with C++ in a few years - what does constexpr do for local variables? constexpr double a0 = 1.5707288;

The compiler can substitute the value how it sees fit. It's like #define, but type-safe and scoped.

Maybe it's folded into expressions, propagated through constant expressions, or used it in contexts that require compile-time constants (template parameters, array sizes, static_assert, other constexpr expressions).

I mean, not in this case of pi/2, where it's more about announcing semantics, but in general those are the purposes and uses.

Re: Even faster asin() was staring right at me

#20
A notable approximation of ~650 AD vintage, by Bhaskara is

   ArcCos(x)= Π √((1-x)/(4+x)).
The search for better and better approximations led Indian mathematicians to independently develop branches of differential and integral calculus.

This tradition came to its own as Madhava school of mathematics from Kerala. https://en.wikipedia.org/wiki/Kerala_school_of_astronomy_and...

Note the approximation is for 0 If I remember correctly, Aryabhatta had derived a rational approximation about a hundred years before this.

EDIT https://doi.org/10.4169/math.mag.84.2.098

Post reply on HN