/*
  FP8_E3M4 playground header file - types & prototypes

  Format: s.eee.mmmm (bias 3)
  Value = (-1)^s*(1+mmmm/16)*2^(eee-3)

  Special cases:
    eee==000 - unnormalized mantissa == (0+0.mmmm)
    0.000.0000 == 0
    s.111.0000 == +/-inf (signed infinity)
    s.111.1xxx == nan (not a number)

  Ranges of values :
    0.000.0001 - smallest unnormalized: (0+1/16)*2^(1-3) == 0.015625  [1/16/4]
    0.000.1111 - largest unnormalized:  (0+15/16)*2^(1-3) == 0.234375 [15/16/4]

    0.001.0000 - smallest normalized:   (1+0/16)*2^(1-3) == 0.25      [16/16/4]
    0.110.1111 - largest normalized:    (1+15/16)*2^(6-3) == 15.5     [31/16*8]

  ------------------------------------------------------------------------
  (C) 2026 Peeter Ellervee <peeter.ellervee@taltech.ee>
*/

#ifndef  _FP8_E3M4_INCLUDED
#define  _FP8_E3M4_INCLUDED

#include <stdlib.h>
#include <math.h>

typedef unsigned char fp8_e3m4;
#define FP8_E3M4_SIGN(N)  ((N&0x80)?1:0)	/* Sign - s == 1/0 */
#define FP8_E3M4_EXP(N)   ((N&0x70)>>4)		/* Exponent - eee  */
#define FP8_E3M4_MANT(N)  (N&0x0f)		/* Mantissa - mmmm */
#define FP8_E3M4_NORM     0x10			/* Extra 1 when normalized */

#define FP8_INFP 0x70
#define FP8_INFN 0xf0
#define FP8_NAN  0x7f

typedef struct { int sign, exp, mant; } fp8_e3m4_str;

/* Unpacking fp8_e3m4 */
extern void fp8_e3m4_unpack(const fp8_e3m4 num, fp8_e3m4_str* data);

/* Packing structure fp8_e3m4_str into fp8_e3m4 */
fp8_e3m4 fp8_e3m4_pack(const fp8_e3m4_str* data);

/*  Converting fp8_e3m4 to float  */
extern float fp8_to_float(const fp8_e3m4 num);

/* Converting float to fp8_e3m4 */
extern fp8_e3m4 float_to_fp8(const float num_in);

/* Adding */
fp8_e3m4 fp8_e3m4_add(const fp8_e3m4 a, const fp8_e3m4 b);

/* Subtracting */
fp8_e3m4 fp8_e3m4_sub(const fp8_e3m4 a, const fp8_e3m4 b);

/* Multiplying */
fp8_e3m4 fp8_e3m4_mul(const fp8_e3m4 a, const fp8_e3m4 b);

/* Dividing */
fp8_e3m4 fp8_e3m4_div(const fp8_e3m4 a, const fp8_e3m4 b);

#endif /*_FP8_E3M4_INCLUDED*/
