{$MODE FPC}
{$MODESWITCH RESULT}
unit dminifloat;

interface

type
TMinifloat = type Byte;

const
  MINIFLOAT_0: TMinifloat = 0;
  MINIFLOAT_PLUS_INF: TMinifloat = 8 + 16 + 32 + 64;
  MINIFLOAT_MINUS_INF: TMinifloat = 8 + 16 + 32 + 64 + 128;
  MINIFLOAT_NAN: TMinifloat = 255;

function MiniFloat(Sign, Exp, Mantissa: LongInt): TMinifloat;

function MiniFloatSign(M: TMinifloat): LongInt;
function MiniFloatExp(M: TMinifloat): LongInt;
function MiniFloatMantissa(M: TMinifloat): LongInt;

function IntToMiniFloat(I: LongInt): TMinifloat;
function MiniFloatToInt(M: TMinifloat): LongInt;

function IsMiniFloatNaN(M: TMinifloat): Boolean; inline;
function IsMiniFloatInf(M: TMinifloat): Boolean; inline;

function MiniFloatToStr(M: TMinifloat; var Buf: array of AnsiChar): LongInt;

implementation

function MiniFloat(Sign, Exp, Mantissa: LongInt): TMinifloat;
begin
  if Sign < 0 then begin
    Result := 128;
  end else
    Result := 0;
  Result := Result or (Exp shl 3) or Mantissa;
end;

function MiniFloatSign(M: TMinifloat): LongInt;
begin
  if M = 0 then begin
    Result := 0;
  end else if M and 128 <> 0 then begin
    Result := -1;
  end else
    Result := 1;
end;

function MiniFloatExp(M: TMinifloat): LongInt;
begin
  Result := (M shr 3) and 15;
end;

function MiniFloatMantissa(M: TMinifloat): LongInt;
begin
  Result := M and 7;
end;

function IntToMiniFloat(I: LongInt): TMinifloat;
begin
  Result := 0;
end;

function MiniFloatToInt(M: TMinifloat): LongInt;
begin
  Result := LongInt(M and 135);
  M := ((M shr 3) and 15);
  if M <> 0 then // normilized number
    Result := Result or 8;
  Result := Result shl M;
end;

function IsMiniFloatNaN(M: TMinifloat): Boolean;
begin
  Result := ((M and 120) = 120) and (M and 7 <> 0);
end;

function IsMiniFloatInf(M: TMinifloat): Boolean;
begin
  Result := (M and 127) = 127;
end;

function MiniFloatToStr(M: TMinifloat; var Buf: array of AnsiChar): LongInt;
begin
  if IsMiniFloatNaN(M) then begin
    Move(PAnsiChar(AnsiString('NaN'))^, Buf[0], 4);
    Exit(3);
  end;
  if M = MINIFLOAT_PLUS_INF then begin
    Move(PAnsiChar(AnsiString('Inf'))^, Buf[0], 4);
    Exit(3);
  end;
  if M = MINIFLOAT_MINUS_INF then begin
    Move(PAnsiChar(AnsiString('-Inf'))^, Buf[0], 5);
    Exit(4);
  end;
  Result := 0;
  if M = 0 then begin
    Move(PAnsiChar(AnsiString('0'))^, Buf[0], 2);
    Exit(1);
  end;
  Result := 0;
  if MiniFloatSign(M) < 0 then begin
    Buf[0] := '-';
    Inc(Result);
  end;
  Buf[Result] := #0;
end;

end.
