本文整理自网络,侵删。
具有16位精度的浮点数主要用于计算机图形学。它们也被称为半精度浮点数(有一半的精度为32位浮点数)。这里有一个符号位,5位指数,还有10位为mantissa。由于有限的精度(在普通的cpus/fpus中没有支持),半浮点数实际上并不是用于计算计算的。在2000年代初,有一半的漂浮物出现在图像和纹理的样本中。float提供的动态范围比常规的8位或16位的整数示例要高。另一方面,常用的单和双精度浮点数的每个像素的内存成本要高得多。一半的浮动有更合理的内存要求,并且它们的精度对于许多在成像方面的应用来说是足够的。多年来,ATI和NVidia GPUs一直支持16bit的浮动格式。我不确定其他的ihv,但是至少Direct3D 10有能力的gpu都应该支持它。如果您对如何在一半和单个精度浮点数之间转换(对象Pascal代码)感兴趣,请继续阅读。最后,半/单转换代码,这里是转换成半浮点数的代码,并返回到单个精度浮点数。它基于OpenEXR库中的C++代码(半类)。首先,一些类型和常量注意到,地中海式的类型只是Word的别名。
type THalfFloat = type Word; const HalfMin: Single = 5.96046448e-08; // Smallest positive half HalfMinNorm: Single = 6.10351562e-05; // Smallest positive normalized half HalfMax: Single = 65504.0; // Largest positive half // Smallest positive e for which half (1.0 + e) != half (1.0) HalfEpsilon: Single = 0.00097656; HalfNaN: THalfFloat = 65535; HalfPosInf: THalfFloat = 31744; HalfNegInf: THalfFloat = 64512;
function FloatToHalf(Float: Single): THalfFloat;var Src: LongWord; Sign, Exp, Mantissa: LongInt;begin Src := PLongWord(@Float)^; // Extract sign, exponent, and mantissa from Single number Sign := Src shr 31; Exp := LongInt((Src and $7F800000) shr 23) - 127 + 15; Mantissa := Src and $007FFFFF; if (Exp > 0) and (Exp < 30) then begin // Simple case - round the significand and combine it with the sign and exponent Result := (Sign shl 15) or (Exp shl 10) or ((Mantissa + $00001000) shr 13); end else if Src = 0 then begin // Input float is zero - return zero Result := 0; end else begin // Difficult case - lengthy conversion if Exp <= 0 then begin if Exp < -10 then begin // Input float's value is less than HalfMin, return zero Result := 0; end else begin // Float is a normalized Single whose magnitude is less than HalfNormMin. // We convert it to denormalized half. Mantissa := (Mantissa or $00800000) shr (1 - Exp); // Round to nearest if (Mantissa and $00001000) > 0 then Mantissa := Mantissa + $00002000; // Assemble Sign and Mantissa (Exp is zero to get denormalized number) Result := (Sign shl 15) or (Mantissa shr 13); end; end else if Exp = 255 - 127 + 15 then begin if Mantissa = 0 then begin // Input float is infinity, create infinity half with original sign Result := (Sign shl 15) or $7C00; end else begin // Input float is NaN, create half NaN with original sign and mantissa Result := (Sign shl 15) or $7C00 or (Mantissa shr 13); end; end else begin // Exp is > 0 so input float is normalized Single // Round to nearest if (Mantissa and $00001000) > 0 then begin Mantissa := Mantissa + $00002000; if (Mantissa and $00800000) > 0 then begin Mantissa := 0; Exp := Exp + 1; end; end; if Exp > 30 then begin // Exponent overflow - return infinity half Result := (Sign shl 15) or $7C00; end else // Assemble normalized half Result := (Sign shl 15) or (Exp shl 10) or (Mantissa shr 13); end; end;end;
function HalfToFloat(Half: THalfFloat): Single;var Dst, Sign, Mantissa: LongWord; Exp: LongInt;begin // Extract sign, exponent, and mantissa from half number Sign := Half shr 15; Exp := (Half and $7C00) shr 10; Mantissa := Half and 1023; if (Exp > 0) and (Exp < 31) then begin // Common normalized number Exp := Exp + (127 - 15); Mantissa := Mantissa shl 13; Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa; // Result := Power(-1, Sign) * Power(2, Exp - 15) * (1 + Mantissa / 1024); end else if (Exp = 0) and (Mantissa = 0) then begin // Zero - preserve sign Dst := Sign shl 31; end else if (Exp = 0) and (Mantissa <> 0) then begin // Denormalized number - renormalize it while (Mantissa and $00000400) = 0 do begin Mantissa := Mantissa shl 1; Dec(Exp); end; Inc(Exp); Mantissa := Mantissa and not $00000400; // Now assemble normalized number Exp := Exp + (127 - 15); Mantissa := Mantissa shl 13; Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa; // Result := Power(-1, Sign) * Power(2, -14) * (Mantissa / 1024); end else if (Exp = 31) and (Mantissa = 0) then begin // +/- infinity Dst := (Sign shl 31) or $7F800000; end else //if (Exp = 31) and (Mantisa <> 0) then begin // Not a number - preserve sign and mantissa Dst := (Sign shl 31) or $7F800000 or (Mantissa shl 13); end; // Reinterpret LongWord as Single Result := PSingle(@Dst)^;end;
program Half_test;{$APPTYPE CONSOLE}{$Include HalfFloat.pas}varX, Z : single;Y : THalfFloat;begin { TODO -oUser -cConsole Main : Insert code here }decimalseparator := ‘.’;x := 1439.156;y := FloatToHalf(X);z := HalfToFloat(y);writeln(x:10:3);writeln(z:10:3);readln;end.
相关阅读 >>
Delphi xe10 文件目录/路径操作 (andorid、ios、windows)
Delphi f1026 file not found: ''quickrpt.dcu''解决方法
更多相关阅读请进入《Delphi》频道 >>