Delphi:如何翻译这个C代码,它对IEEE浮点数进行低级访问?

Ast*_*oth 3 delphi

以下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专家愿意提供帮助.

更多信息

我稍后会添加此部分,这不是问题的一部分.本节为希望获得更高准确性的读者提供信息.

Dav*_*nan 8

我想我会通过使用指针强制转换来对其进行编码以实现重新解释转换:

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用作基础.


Ond*_*lle 5

这个怎么样:

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)