Below is Delphi / IA32 & x87 code used to encode Double to Float16 and decode Float16 to Double (actually extended [80-bit] in this case). Hopefully someone will find it useful.
Compatibility at a player level would be a great starting point (i.e. simply playing a RIFF WAVE with wFormatTag=0x0003 and wBitsPerSample=0x0010).
[!--sizeo:1--][span style=\"font-size:8pt;line-height:100%\"][!--/sizeo--]
//==============================================================================
//
// Float16 encode / decode functions;
//
// 2011 Nick Currie
//
//==============================================================================
Type
Float16 = Word;
SingleRec = Packed Record
Case Integer of
1:(Single : Single);
2:(Integer : Integer);
3:(Words : Array[0..1] of Word);
4:(BytePx : Byte; WordP1 : Word;);
5:(Bytes : Array[0..3] of Byte);
End;
DoubleRec = Packed Record
Case Integer of
1:(Double : Double);
2:(Int64 : Int64);
3:(Integers : Array[0..1] of Integer);
4:(Words : Array[0..3] of Word);
5:(BytePx : Byte; WordP1,WordP3,WordP5 : Word;);
6:(Bytes : Array[0..7] of Byte);
End;
ExtendedRec = Packed Record
Case Integer of
1:(Extended : Extended);
2:(Int64 : Int64);
3:(Integers : Array[0..1] of Integer);
4:(Words : Array[0..4] of Word);
5:(Bytes : Array[0..9] of Byte);
End;
Var
Powersof = Packed Record
two : array[-1024..1023] of Double;
End;
{$IFNDEF USEASM}
//============================================================================
Function F80_to_F16(F80_Value : Extended) : Float16;
//============================================================================
Var
Exponent : Integer;
Sign : Word;
Begin
//============================================================================
Sign:=ExtendedRec(F80_Value).Words[4] and $8000;
If (F80_Value=0) then
F80_to_F16:=Sign
else
Begin
Exponent:=(ExtendedRec(F80_Value).Words[4] and $7FFF)-$3FFF;
ExtendedRec(F80_Value).Words[4]:=ExtendedRec(F80_Value).Words[4] or $3FFF;
if Exponent>15 then
F80_to_F16:=Sign or $7C00
else
If (Exponent>-15) then
F80_to_F16:=(Sign or ((Exponent+15) shl 10) or ((ExtendedRec(F80_Value).Words[3] and $7FFF) shr 5))
else
if Exponent>-25 then
F80_to_F16:=(Sign or (ExtendedRec(F80_Value).Words[3] shr (-Exponent-9)))
else
F80_to_F16:=Sign;
End;
//============================================================================
End;
//============================================================================
{$ELSE}
//============================================================================
Function F80_to_F16(F80_Value : Extended) : Float16; Assembler;
//============================================================================
asm
push ecx
push edx
xor eax,eax
xor edx,edx
mov cx,word ptr F80_Value+8
mov dh,ch
and dh,$80
and cx,$7FFF
jz @@EX
sub cx,$3FFF
cmp cx,-$19
jle @@EX
mov ah,$7C
cmp cx,$10
jge @@EX
@@01: mov ax,word ptr F80_Value+6
cmp cx,-$0F
jg @@02
neg cl
sub cl,$09
shr eax,cl
jmp @@EX
@@02: add cl,$0F
shr ax,$05
shl cl,$02
and ax,$03FF
or ah,cl
@@EX: or ax,dx
pop edx
pop ecx
End;
//============================================================================
{$ENDIF}
{$IFNDEF USEASM}
//============================================================================
Function F64_to_F16(F64_Value : Double) : Float16;
//============================================================================
Var
Exponent : Integer;
Sign : Word;
Begin
//============================================================================
DoubleRec(F64_Value).Double:=F64_Value;
Sign:=DoubleRec(F64_Value).Words[3] and $8000;
If (F64_Value=0) then
F64_to_F16:=Sign
else
Begin
Exponent:=(((DoubleRec(F64_Value).Words[3] and $7FF0) shr 4)-$3FF);
DoubleRec(F64_Value).Words[3]:=((DoubleRec(F64_Value).Words[3] and $000F) or $3FF0);
if Exponent>15 then
F64_to_F16:=Sign or $7C00
else
If (Exponent>-15) then
F64_to_F16:=(Sign or ((Exponent+15) shl 10) or ((DoubleRec(F64_Value).WordP5 shr 2) and $3FF))
else
if Exponent>-25 then
F64_to_F16:=(Sign or (((DoubleRec(F64_Value).WordP5 or $1000) and $1FFE) shr (-Exponent-12)))
else
F64_to_F16:=Sign;
End;
//============================================================================
End;
//============================================================================
{$ELSE}
//============================================================================
Function F64_to_F16(F64_Value : Double) : Float16; Assembler;
//============================================================================
asm
push ecx
push edx
xor edx,edx
xor eax,eax
mov cx,word ptr F64_Value+6
mov dh,ch
and dh,$80
and cx,$7FF0
jz @@EX
shr cx,4
sub cx,$3FF
cmp cx,-$19
jle @@EX
mov ah,$7C
cmp cx,$10
jge @@EX
@@01: mov ax,word ptr F64_Value+5
shr ax,2
and ax,$03FF
cmp cx,-$0F
jg @@02
or ah,$04
neg cl
and ax,$07FF
sub cl,14
shr eax,cl
jmp @@EX
@@02: add cl,15
shl cl,2
or ah,cl
@@EX: or ax,dx
pop edx
pop ecx
End;
//============================================================================
{$ENDIF}
{$IFNDEF USEASM}
//============================================================================
Function F16_to_F80(F16_Value : Float16) : Extended;
//============================================================================
Begin
//============================================================================
if F16_Value and $8000<>0 then
Begin
if ((F16_Value and $7FFF)=0) then
F16_to_F80:=-0
else
if ((F16_Value and $7C00)=0) then
F16_to_F80:=-(F16_Value and $3FF)*powersof.two[-24]
else
F16_to_F80:=-((F16_Value and $3FF) or $400)*powersof.two[((F16_Value shr 10) and $1F)-25]
End
else
Begin
if F16_Value=0 then
F16_to_F80:=0
else
if ((F16_Value and $7C00)=0) then
F16_to_F80:=(F16_Value and $3FF)*powersof.two[-24]
else
F16_to_F80:=((F16_Value and $3FF) or $400)*powersof.two[((F16_Value shr 10) and $1F)-25]
End;
//============================================================================
End;
//============================================================================
{$ELSE}
//============================================================================
Function F16_to_F80(F16_Value : Float16) : Extended;
//============================================================================
asm
push ecx
push edx
movzx eax,F16_Value
mov dl,ah
and ax,$7FFF
jnz @@01
fldz
jmp @@EX
@@01: fld1
test dl,$80
jz @@02
fchs
@@02: mov ecx,eax
and ax,$3FF
shr cx,10
mov edx,1000
push eax
and cl,$1F
jz @@03
or word ptr [esp],$400
mov dx,999
add dx,cx
@@03: fimul dword ptr [esp]
fmul qword ptr powersof.two[edx*double_size]
@@04: pop eax
@@EX: pop edx
pop ecx
//============================================================================
End;
//============================================================================
{$ENDIF}
[/size] [edit] Code update. [/edit]