以下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;
}
Run Code Online (Sandbox Code Playgroud)
我知道C union可以翻译成Delphi变体记录,但是我仍然难以将这种低级C代码翻译成Delphi.我希望这里的Delphi专家愿意提供帮助.
我稍后会添加此部分,这不是问题的一部分.本节为希望获得更高准确性的读者提供信息.
fasterlog2()故意设计为更简单,更快但不太准确的Log2功能.任何期望更高准确度的人都可以使用他们提供的更准确的功能,即fastlog2().126.94269504.Mathematica网站为.nb文件提供免费查看器.我想我会通过使用指针强制转换来对其进行编码以实现重新解释转换:
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;
Run Code Online (Sandbox Code Playgroud)
请注意,我使用类型的类型常量single来确保与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;
Run Code Online (Sandbox Code Playgroud)
对于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;
Run Code Online (Sandbox Code Playgroud)
在x64中,汇编版本的性能仅为纯pascal函数的两倍.x86汇编版本的性能超过了五倍 - 这完全是由于SSE与x87中类型转换(整数/单/双)的成本较高.
可以使用此方法的原因是浮点数表示为
significand * base^exponent
Run Code Online (Sandbox Code Playgroud)
并且值2用作基础.
这个怎么样:
function fasterlog2(x: Single): Single; inline;
const
f1: Single = 1.1920928955078125e-7;
f2: Single = -126.94269504;
var
i: Cardinal absolute x;
begin
Result := i * f1 + f2;
end;
Run Code Online (Sandbox Code Playgroud)