Skip to content

Instantly share code, notes, and snippets.

@markusl
Created August 24, 2011 18:25
Show Gist options
  • Save markusl/1168776 to your computer and use it in GitHub Desktop.
Save markusl/1168776 to your computer and use it in GitHub Desktop.
Implementing the Fast inverse square root (InvSqrt) in F#
#load "FsharpChart.fsx"
open MSDN.FSharp.Charting
let castValue (value : 'TSource) :'TResult =
let an = new System.Reflection.AssemblyName("CastUtil")
let ab = System.AppDomain.CurrentDomain.DefineDynamicAssembly(an, System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave)
let mb = ab.DefineDynamicModule(an.Name)
let tb = mb.DefineType("CastUtil", System.Reflection.TypeAttributes.Public ||| System.Reflection.TypeAttributes.Class)
let fb = tb.DefineMethod("Read", System.Reflection.MethodAttributes.Public ||| System.Reflection.MethodAttributes.Static, typeof<'TResult>, ([|typeof<'TSource>|]))
let ig = fb.GetILGenerator()
ig.Emit(System.Reflection.Emit.OpCodes.Ldarg_0)
let local = ig.DeclareLocal(typeof<'TSource>)
ig.Emit(System.Reflection.Emit.OpCodes.Stloc, local)
ig.Emit(System.Reflection.Emit.OpCodes.Ldloca_S, local)
ig.Emit(System.Reflection.Emit.OpCodes.Ldobj, typeof<'TResult>)
ig.Emit(System.Reflection.Emit.OpCodes.Ret)
let cl = tb.CreateType()
let readMethod = cl.GetMethod("Read", System.Reflection.BindingFlags.Static ||| System.Reflection.BindingFlags.Public)
readMethod.Invoke(null, [|value|]) :?> 'TResult
let readPtr1 (value : nativeptr<'TSource>) :'TResult = (# "ldobj !0" type ('TResult) value : 'TResult #)
let invsqrt_1 xx =
let halfx = 0.5F * xx
let mutable x = xx
let mutable i = (0x5f3759df) - ((readPtr1 &&x) >>> 1)
x <- readPtr1 &&i
x * (1.5F - halfx*x*x)
let invsqrt_2 xx =
let halfx = 0.5F * xx
let x:int = castValue xx
let mutable i = (0x5f3759df) - (x >>> 1)
let x:float32 = castValue i
x * (1.5F - halfx*x*x)
let z = 0.1
let y:int = castValue z
let normal = 1./System.Math.Sqrt(0.01)
let fast = invsqrt_2 0.01F
printfn "%f %f" normal fast
let getValue x =
let fast = (invsqrt (x))
let slow = (1./(System.Math.Sqrt((float)x)))
fast - (float32)slow
[for x in 0.01 .. 0.001 ..10. -> getValue ((float32)x)] |> FSharpChart.Line
// See http://jheriko-rtw.blogspot.com/2009/04/understanding-and-improving-fast.html
// for original algorithm
@markusl
Copy link
Author

markusl commented Sep 30, 2011

Keep in mind that this is just a WIP version of proof-of-concept of how to implement/use "pointers" in F#. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment