unit dieee754;

{$MODE FPC}
{$MODESWITCH DEFAULTPARAMETERS}
{$MODESWITCH OUT}
{$MODESWITCH RESULT}



interface

const
  MIN_FLOAT32 = - 3.402823466e+38;
  MAX_FLOAT32 =   3.402823466e+38;

// Assemble -- build from parts
// Encode
// Get

procedure AssembleFloat32(SignBit, ExponentPart, MantissaPart: UInt32;
                          out Result); inline;
//
//  Assembles a floating-point number from its parts. Note that parts should be
//  normilized, that is resulting value is
//
//    for ExponentPart=0
//      Result := (-1)^SignBit * 2^(-126) * (0.MantissaPart)
//
//    for $01<=ExponentPart<=$FE
//      Result := (-1)^SignBit * 2^(ExponentPart - 127) * (1<<24 + MantissaPart)
//
//    for ExponentPart=$FF
//      for Mantissa= : +-Infinitity
//      for Mantissa= : +-NaN
//
//  Use GetFloat32 function which takes actual exponent and mantissa.
//

function EncodeFloat32(Significand, Exponent: Int32): Single; inline;
//
//  Result := Significand * 2^Exponent
//
//  May return -Inf or +Inf if the value is too big.
//

function DecodeFloat32(F: Single; out Significand, Exponent: Int32): Boolean;
//
//  When returns Result=True:
//
//      Significand and Exponent such as F = Significand * 2^Exponent
//
//  when returns Result=False:
//
//      F contains neither subnormal nor normal value, Significand=0 and Exponent=0
//
//

//procedure EncodeFloat32(SignBit, Exponent, Mantissa: Int32;
//                        out Result: Single); inline;
//
//    Result := (-1)^SignBit * Mantissa * 2^Exponent
//

//function GetFloat64(SignBit, Exponent, Mantissa: Int64): Double; inline;
//procedure EncodeFloat64(SignBit, Exponent, Mantissa: Int64;
//                        out Result: Double); inline;
//
//    Result := (-1)^SignBit * Mantissa * 2^Exponent
//

function NextFloat32(var F: Single): Boolean; inline;



implementation

procedure AssembleFloat32(SignBit, ExponentPart, MantissaPart: UInt32;
                          out Result); inline;
begin
  PUInt32(@Result)^ := ((SignBit and 1) shl 31) or
                       ((ExponentPart and %11111111) shl 24) or
                       (MantissaPart and $FFF);
end;

function _EncodeFloat32Internal(Significand: UInt32; Exponent: Int32; SignMask: UInt32): UInt32; inline;
begin
  if Significand >= (1 shl 24) - 1 then begin // normalize significand to 22 bits
    if Exponent > 127 + 33 then // protection of overflow in the following loop
      Exit(SignMask or (UInt32($FF) shl 23)); // +-INF
    while Significand > (1 shl 24) - 1 do begin
      Significand := Significand shr 1;
      Inc(Exponent);
    end;
  end else begin
    if Exponent < -126 - 33 then // protection of unverflow in the following loop
      Exit(SignMask); // +-0
    while Significand < (1 shl 23) - 1 do begin
      Significand := Significand shl 1;
      Dec(Exponent);
    end;
  end;

  if Exponent <= -126 then begin // subnormal?
    Writeln('Subnormal ', Exponent, ' ', Significand and $3FFFFF, ' ', SignMask);
    Exit(SignMask or ((Significand shr (- Exponent - 126)) and $3FFFFF));
  end else if Exponent <= 127 then begin // normal?
    // Writeln('Normal ', Exponent, ' ', Significand and $3FFFFF, ' ', SignMask);
    Exit(SignMask or ((Exponent + 127 + 23) shl 23) or (Significand and $3FFFFF));
  end else begin // +-INF
    Exit(SignMask or ($FF shl 23));
  end;
end;

function EncodeFloat32(Significand, Exponent: Int32): Single; inline;
begin
  if Significand = 0 then
    Exit(0.0);
  PUInt32(@Result)^ := _EncodeFloat32Internal(Abs(Significand),
                                              Exponent,
                                              UInt32(Significand) and (1 shl 31));
end;

function DecodeFloat32(F: Single; out Significand, Exponent: Int32): Boolean;
begin
  Exponent := (PUInt32(@F)^ shr 23) and $FF;
  if Exponent > $FE then begin
    Significand := 0;
    Exponent := 0;
    Exit(False);
  end else if Exponent = 0 then begin
    Significand := PUInt32(@F)^ and $003FFFFF;
    if F < 0 then
      Significand := - Significand;
    Exponent := -126 - 23;
    Exit(True);
  end else begin
    Significand := (PUInt32(@F)^ and $003FFFFF) or (1 shl 23);
    if F < 0 then
      Significand := - Significand;
    Dec(Exponent, 127 + 23);
    Exit(True);
  end;
end;

//function EncodeFloat64(SignBit, Exponent, Mantissa: Int64): Double; inline;
//begin
//  PUInt64(@Result)^ := ((UInt64(SignBit and 1) shl 63) or
//                       ((UInt64(Exponent + 1023) and %11111111111) shl 24) or
//                       (Mantissa and ((1 shl 54) - 1));
//end;

//procedure EncodeFloat64(SignBit, Exponent, Mantissa: Int64;
//                        out Result: Double); inline;
//begin
//  PUInt64(@Result)^ := ((UInt64(SignBit and 1) shl 63) or
//                       ((UInt64(Exponent + 1023) and %11111111111) shl 24) or
//                       (Mantissa and ((1 shl 54) - 1));
//end;

function NextFloat32(var F: Single): Boolean; inline;
begin
  Inc(PUInt32(@F)^);
  Exit(F <= MAX_FLOAT32);
end;

end.
