Skip to content

Instantly share code, notes, and snippets.

@r1pper
Last active October 31, 2023 15:34
Show Gist options
  • Save r1pper/b8f4620a8f7718b16df9 to your computer and use it in GitHub Desktop.
Save r1pper/b8f4620a8f7718b16df9 to your computer and use it in GitHub Desktop.
Fast float Logarithm in C# using lookup Table
using System;
using System.Runtime.InteropServices;
namespace Test2
{
public static class FastLog
{
[StructLayout(LayoutKind.Explicit)]
private struct Ieee754
{
[FieldOffset(0)] public float Single;
[FieldOffset(0)] public uint UnsignedBits;
[FieldOffset(0)] public int SignedBits;
public uint Sign
{
get
{
return UnsignedBits >> 31;
}
}
public int Exponent
{
get
{
return (SignedBits >> 23) & 0xFF;
}
}
public uint Mantissa
{
get
{
return UnsignedBits & 0x007FFFFF;
}
}
}
private static readonly float[] MantissaLogs = new float[(int) Math.Pow(2, 23)];
private const float Base10 = 3.321928F;
private const float BaseE = 1.442695F;
static FastLog()
{
//creating lookup table
for (uint i = 0; i < MantissaLogs.Length; i++)
{
var n = new Ieee754 {UnsignedBits = i | 0x3F800000}; //added the implicit 1 leading bit
MantissaLogs[i] = (float) Math.Log(n.Single, 2);
}
}
public static float Log2(float value)
{
if (value == 0F)
return float.NegativeInfinity;
var number = new Ieee754 {Single = value};
if (number.UnsignedBits >> 31 == 1) //NOTE: didn't call Sign property for higher performance
return float.NaN;
return (((number.SignedBits >> 23) & 0xFF) - 127) + MantissaLogs[number.UnsignedBits & 0x007FFFFF];
//NOTE: didn't call Exponent and Mantissa properties for higher performance
}
public static float Log10(float value)
{
return Log2(value)/Base10;
}
public static float Ln(float value)
{
return Log2(value)/BaseE;
}
public static float Log(float value, float valueBase)
{
return Log2(value)/Log2(valueBase);
}
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace Test2
{
class Program
{
private static void Main(string[] args)
{
var watch = new Stopwatch();
FastLog.Log2(1); //create table for the fist time
Console.WriteLine("benchmarking .net log10...");
var doubleValue = 1.0;
watch.Reset();
watch.Start();
for (var i = 0; i < 1000000000; i++)
{
Math.Log10(doubleValue);
doubleValue+=1.0;
}
watch.Stop();
var netTime = watch.Elapsed;
Console.WriteLine("result: {0}", netTime);
Console.WriteLine("benchmarking fast log10...");
var floatValue = 1.0F;
watch.Reset();
watch.Start();
for (var i = 0; i < 1000000000; i++)
{
FastLog.Log10(floatValue);
floatValue += 1.0F;
}
watch.Stop();
var fastTime = watch.Elapsed;
Console.WriteLine("result: {0}", fastTime);
Console.WriteLine("ratio: {0}", netTime.TotalMilliseconds / (float)fastTime.TotalMilliseconds);
Console.WriteLine("done.");
Console.ReadKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment