/*
  FP8_E3M4 playground header file - functions

  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>
*/

#ifdef DEBUGGING
#include <stdio.h>
#endif /*DEBUGGING*/

#include "fp8_e3m4.h"


/*
 * Adding
 */
fp8_e3m4 fp8_e3m4_add(const fp8_e3m4 a, const fp8_e3m4 b) {
  fp8_e3m4_str a_str, b_str, s_str={0,0,0};
  fp8_e3m4_unpack(a,&a_str);			/* Unpacking operands */
  fp8_e3m4_unpack(b,&b_str);

  /*
   * Enter your code here...
   */

#ifdef DEBUGGING
  printf("**fp8_e3m4_add** %d %d %d: %d %d %d: %d %d %d\n",
	 a_str.sign,a_str.exp,a_str.mant,
	 b_str.sign,b_str.exp,b_str.mant,
	 s_str.sign,s_str.exp,s_str.mant);
#endif /*DEBUGGING*/

  return fp8_e3m4_pack(&s_str);			/* Packing... */
}

  
/*
 * Subtracting
 */
fp8_e3m4 fp8_e3m4_sub(const fp8_e3m4 a, const fp8_e3m4 b) {
  fp8_e3m4_str a_str, b_str, s_str={0,0,0};
  fp8_e3m4_unpack(a,&a_str);			/* Unpacking operands */
  fp8_e3m4_unpack(b,&b_str);

  /*
   * Enter your code here...
   */

#ifdef DEBUGGING
  printf("**fp8_e3m4_sub** %d %d %d: %d %d %d: %d %d %d\n",
	 a_str.sign,a_str.exp,a_str.mant,
	 b_str.sign,b_str.exp,b_str.mant,
	 s_str.sign,s_str.exp,s_str.mant);
#endif /*DEBUGGING*/

  return fp8_e3m4_pack(&s_str);			/* Packing... */
}


/*
 * Multiplying
 */
fp8_e3m4 fp8_e3m4_mul(const fp8_e3m4 a, const fp8_e3m4 b) {
  fp8_e3m4_str a_str, b_str, m_str={0,0,0};
  fp8_e3m4_unpack(a,&a_str);			/* Unpacking operands */
  fp8_e3m4_unpack(b,&b_str);

  /*
   * Enter your code here...
   */

#ifdef DEBUGGING
  printf("**fp8_e3m4_mul** %d %d %d: %d %d %d: %d %d %d\n",
	 a_str.sign,a_str.exp,a_str.mant,
	 b_str.sign,b_str.exp,b_str.mant,
	 m_str.sign,m_str.exp,m_str.mant);
#endif /*DEBUGGING*/

  return fp8_e3m4_pack(&m_str);			/* Packing... */
}


/*
 * Dividing
 */
fp8_e3m4 fp8_e3m4_div(const fp8_e3m4 a, const fp8_e3m4 b) {
  fp8_e3m4_str a_str, b_str, m_str={0,0,0};
  fp8_e3m4_unpack(a,&a_str);			/* Unpacking operands */
  fp8_e3m4_unpack(b,&b_str);

  if (a_str.sign!=b_str.sign) m_str.sign=1;	/* Adjusting sign */
  if (b_str.mant==0)				/* Dividing by 0? */
    { if (m_str.sign) return FP8_INFN; else return FP8_INFP; }
  m_str.exp=a_str.exp-b_str.exp;		/* Subtracting exponents */
  a_str.mant=a_str.mant<<4;			/* Adjusting range */
  m_str.mant=a_str.mant/b_str.mant;		/* Dividing mantissas */

#ifdef DEBUGGING
  printf("**fp8_e3m4_div** %d %d %d: %d %d %d: %d %d %d\n",
	 a_str.sign,a_str.exp,a_str.mant,
	 b_str.sign,b_str.exp,b_str.mant,
	 m_str.sign,m_str.exp,m_str.mant);
#endif /*DEBUGGING*/

  return fp8_e3m4_pack(&m_str);			/* Packing... */
}
