comp.lang.ada
 help / color / mirror / Atom feed
* Quick inverse square root
@ 2021-01-02 22:26 Matt Borchers
  2021-01-02 23:18 ` Jeffrey R. Carter
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Matt Borchers @ 2021-01-02 22:26 UTC (permalink / raw)


I'm sure many of you have seen the Fast Inverse SquareRoot algorithm from the open source Quake III engine.  I just encountered it a few days ago.  Here it is, a bit reduced, from the original source:

    //C code from Quake III engine
    float Q_rsqrt( float number )
    {
       long i;
       float x2, y;
       const float threehalfs = 1.5F;
    
       x2 = number * 0.5F;
       y = number;
       i = *(long *) &y;
       i = 0x5f3759df - ( i >> 1 );
       y = *(float *) &i;
       y = y * (threehalfs - (x2 * y * y));
       return y;
    }

It is interesting how much clearer the Ada code version is:

    with Interfaces; use Interfaces;
    function QUICK_INVERSE_SQRT( a : FLOAT ) return FLOAT is
        y : FLOAT := a;
        i : UNSIGNED_32;
        for i'Address use y'Address;
    begin
        i := 16#5F3759DF# - shift_right( i, 1 );
        return y * (1.5 - (0.5 * a * y * y));
    end QUICK_INVERSE_SQRT;

The magic hexadecimal number is calculated from the formula:

  3/2 * 2**23 * (127 - mu) where mu is a constant close to 0.043.

My question is that I am trying to get this to work for Long_Float but I'm not having any luck.  I would expect that everything should be the same in the algorithm except for the types (Float -> Long_Float and Unsigned_32 -> Unsigned_64) and the "magic" hexadecimal number that should be calculated from the same formula but adjusted for the Long_Float bit layout.

    3/2 * 2**52 * (1023 - mu) where mu is the identical constant as used for Float case.

This doesn't seem to work and I haven't been able to find my error.  I'm sure it is something silly.  Does anybody have a suggestion?

A second question I have is how to make this a generic for any Floating point type.  I can only think that I have to provide three things: not only the obvious Float type, but also the Unsigned type of the same size, as well as the hex constant.

    generic
        type F is digits <>;
        type U is mod <>;
        magic : U;
    function G_Q_INV_SQRT( a : F ) return F;

I write the body like this:

    function G_Q_INV_SQRT( a : F ) return F is
        y : F := a;
        i : U;
        for i'Address use y'Address;
    begin
        i := magic - shift_right( i, 1 );
        return y * (1.5 - (0.5 * a * y * y));
    end G_Q_INV_SQRT;

    function QUICK_INVERSE_SQRT is
        new G_Q_INV_SQRT( FLOAT, UNSIGNED_32, 16#5F3759DF# );

This won't compile because the type U is not valid for the call to "shift_right".  How do I overcome this obstacle?

Once that is overcome, is there a way I can eliminate having to pass in the unsigned type along with the floating point type?  That seems like the programmer would require internal knowledge to make use of the generic.  Any thoughts on how to get the compiler to compute the magic number in the generic at compile time?

Thanks,
Matt

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-01-07 17:49 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-02 22:26 Quick inverse square root Matt Borchers
2021-01-02 23:18 ` Jeffrey R. Carter
2021-01-03 10:58 ` Dmitry A. Kazakov
2021-01-03 22:31   ` Matt Borchers
2021-01-03 23:47     ` Jeffrey R. Carter
2021-01-04  3:50       ` Matt Borchers
2021-01-04  4:28         ` Matt Borchers
2021-01-04 11:04         ` Jeffrey R. Carter
2021-01-04 11:13     ` AdaMagica
2021-01-04 11:28       ` AdaMagica
2021-01-04 12:13         ` Dmitry A. Kazakov
2021-01-04 13:39 ` Egil H H
2021-01-04 20:55   ` Matt Borchers
2021-01-04 21:06     ` Paul Rubin
2021-01-05  2:22       ` Matt Borchers
2021-01-07 17:49     ` Brian Drummond

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox