以下C函数来自 fastapprox项目. static inline float fasterlog2 (float x){ union { float f; uint32_t i; } vx = { x }; float y = vx.i; y *= 1.1920928955078125e-7f; return y - 126.94269504f;} 我知道C union可以翻译成Delphi变体记录
static inline float fasterlog2 (float x) { union { float f; uint32_t i; } vx = { x }; float y = vx.i; y *= 1.1920928955078125e-7f; return y - 126.94269504f; }
我知道C union可以翻译成Delphi变体记录,但是我仍然难以将这种低级C代码翻译成Delphi.我希望这里的Delphi专家愿意提供帮助.
更多信息
我稍后会添加此部分,这不是问题的一部分.本节为希望获得更高准确性的读者提供信息.
>在fastapprox中,quicklog2()被故意设计为更简单,更快但不太准确的Log2功能.任何期望更高准确度的人都可以使用他们提供的更准确的功能,即fastlog2().
>他们包括一个Mathematica notebook,解释了他们的算法以及一些神秘值的起源,例如:126.94269504. Mathematica website为.nb文件提供免费查看器.
>另见:Why the IEEE-754 exponent bias used in this C code is 126.94269504 instead of 127?
function fasterlog2(x: single): single; const c1: Single = 1.1920928955078125e-7; c2: Single = 126.94269504; var y: single; begin y := PCardinal(@x)^; Result := y * c1 - c2; end;
请注意,我使用了type类型的类型常量来确保与C代码完全匹配.
我真的不认为在Delphi实现中需要变量记录.
或者你可以使用纯粹的asm方法. x86版本如下所示:
function fasterlog2asm(x: single): single; const c1: Single = 1.1920928955078125e-7; c2: Single = 126.94269504; asm FILD DWORD PTR [ESP+$08] FMUL c1 FSUB c2 FWAIT end;
对于x64,SSE实现将是
function fasterlog2asm64(x: single): single; const c1: double = 1.1920928955078125e-7; c2: double = 126.94269504; asm CVTDQ2PD xmm0, xmm0 MULSD xmm0, c1 SUBSD xmm0, c2 CVTSD2SS xmm0, xmm0 end;
在x64中,汇编版本的性能仅为纯pascal函数的两倍. x86汇编版本的性能超过了五倍 – 这完全是由于SSE与x87中类型转换(整数/单/双)的成本较高.
可以使用此方法的原因是浮点数表示为
significand * base^exponent
并且值2用作基础.