added support for berkeley softfloat 3
authorBill Zorn <bill.zorn@gmail.com>
Thu, 2 Aug 2018 22:55:28 +0000 (15:55 -0700)
committerBill Zorn <bill.zorn@gmail.com>
Thu, 2 Aug 2018 22:55:28 +0000 (15:55 -0700)
setup.py
sfpy/__init__.py
sfpy/cfloat.pxd [new file with mode: 0644]
sfpy/float.pyx [new file with mode: 0644]

index 2aa76e2000fcfb20a16ff985d9d2742f9c8646ea..794896491adc1df27eb08fd373295a6e793350dd 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -9,6 +9,12 @@ posit_ext = Extension(
     libraries=['m'],
 )
 
+float_ext = Extension(
+    'sfpy.float', ['sfpy/float.pyx'],
+    include_dirs=['berkeley-softfloat-3/source/include/'],
+    extra_objects=['./berkeley-softfloat-3/build/Linux-x86_64-GCC/softfloat.a'],
+)
+
 setup(
     name='sfpy',
     version='0.1.0',
@@ -17,5 +23,5 @@ setup(
     author_email='bill.zorn@gmail.com',
     url='https://github.com/billzorn/sfpy',
     packages=['sfpy'],
-    ext_modules=cythonize([posit_ext]),
+    ext_modules=cythonize([posit_ext, float_ext]),
 )
index d213f2ba84fca2bab57d41c992955b28d844f8cb..77dba9745783bcd50eaee29da3650b33429bd8fb 100644 (file)
@@ -4,3 +4,5 @@ mypath = os.path.abspath(os.path.dirname(__file__))
 print('hi from module sfpy @ {:s}'.format(mypath))
 
 from .posit import Posit8, Quire8, Posit16, Quire16
+
+from .float import Float16, Float32, Float64
diff --git a/sfpy/cfloat.pxd b/sfpy/cfloat.pxd
new file mode 100644 (file)
index 0000000..dc00f24
--- /dev/null
@@ -0,0 +1,334 @@
+from libc.stdint cimport *
+
+# For bitwise conversion between Python floats and the uint containers
+# needed to construct softfloat representations.
+ctypedef union ui64_double:
+    uint64_t u;
+    double d;
+
+cdef extern from '../berkeley-softfloat-3/source/include/softfloat.h':
+
+    # Transparent types so we can have access to the raw bits.
+
+    ctypedef struct float16_t:
+        uint16_t v;
+
+    ctypedef struct float32_t:
+        uint32_t v;
+
+    ctypedef struct float64_t:
+        uint64_t v;
+
+    ctypedef struct float128_t:
+        uint64_t v[2];
+
+    # /*----------------------------------------------------------------------------
+    # | Software floating-point underflow tininess-detection mode.
+    # *----------------------------------------------------------------------------*/
+    # extern uint_fast8_t softfloat_detectTininess; # THREAD_LOCAL
+    # cdef enum:
+    #     softfloat_tininess_beforeRounding = 0
+    #     softfloat_tininess_afterRounding  = 1
+
+    # /*----------------------------------------------------------------------------
+    # | Software floating-point rounding mode.  (Mode "odd" is supported only if
+    # | SoftFloat is compiled with macro 'SOFTFLOAT_ROUND_ODD' defined.)
+    # *----------------------------------------------------------------------------*/
+    extern uint_fast8_t softfloat_roundingMode; # THREAD_LOCAL
+    cdef enum:
+        softfloat_round_near_even   = 0
+        softfloat_round_minMag      = 1
+        softfloat_round_min         = 2
+        softfloat_round_max         = 3
+        softfloat_round_near_maxMag = 4
+        # softfloat_round_odd         = 6
+
+    # /*----------------------------------------------------------------------------
+    # | Software floating-point exception flags.
+    # *----------------------------------------------------------------------------*/
+    extern uint_fast8_t softfloat_exceptionFlags; # THREAD_LOCAL
+    cdef enum:
+        softfloat_flag_inexact   =  1
+        softfloat_flag_underflow =  2
+        softfloat_flag_overflow  =  4
+        softfloat_flag_infinite  =  8
+        softfloat_flag_invalid   = 16
+
+    # /*----------------------------------------------------------------------------
+    # | Routine to raise any or all of the software floating-point exception flags.
+    # *----------------------------------------------------------------------------*/
+    void softfloat_raiseFlags( uint_fast8_t );
+
+    # /*----------------------------------------------------------------------------
+    # | Integer-to-floating-point conversion routines.
+    # *----------------------------------------------------------------------------*/
+    float16_t ui32_to_f16( uint32_t );
+    float32_t ui32_to_f32( uint32_t );
+    float64_t ui32_to_f64( uint32_t );
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # extFloat80_t ui32_to_extF80( uint32_t );
+    # float128_t ui32_to_f128( uint32_t );
+    # #endif
+    # void ui32_to_extF80M( uint32_t, extFloat80_t * );
+    # void ui32_to_f128M( uint32_t, float128_t * );
+    float16_t ui64_to_f16( uint64_t );
+    float32_t ui64_to_f32( uint64_t );
+    float64_t ui64_to_f64( uint64_t );
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # extFloat80_t ui64_to_extF80( uint64_t );
+    # float128_t ui64_to_f128( uint64_t );
+    # #endif
+    # void ui64_to_extF80M( uint64_t, extFloat80_t * );
+    # void ui64_to_f128M( uint64_t, float128_t * );
+    float16_t i32_to_f16( int32_t );
+    float32_t i32_to_f32( int32_t );
+    float64_t i32_to_f64( int32_t );
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # extFloat80_t i32_to_extF80( int32_t );
+    # float128_t i32_to_f128( int32_t );
+    # #endif
+    # void i32_to_extF80M( int32_t, extFloat80_t * );
+    # void i32_to_f128M( int32_t, float128_t * );
+    float16_t i64_to_f16( int64_t );
+    float32_t i64_to_f32( int64_t );
+    float64_t i64_to_f64( int64_t );
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # extFloat80_t i64_to_extF80( int64_t );
+    # float128_t i64_to_f128( int64_t );
+    # #endif
+    # void i64_to_extF80M( int64_t, extFloat80_t * );
+    # void i64_to_f128M( int64_t, float128_t * );
+
+    # /*----------------------------------------------------------------------------
+    # | 16-bit (half-precision) floating-point operations.
+    # *----------------------------------------------------------------------------*/
+    uint_fast32_t f16_to_ui32( float16_t, uint_fast8_t, bint );
+    uint_fast64_t f16_to_ui64( float16_t, uint_fast8_t, bint );
+    int_fast32_t f16_to_i32( float16_t, uint_fast8_t, bint );
+    int_fast64_t f16_to_i64( float16_t, uint_fast8_t, bint );
+    uint_fast32_t f16_to_ui32_r_minMag( float16_t, bint );
+    uint_fast64_t f16_to_ui64_r_minMag( float16_t, bint );
+    int_fast32_t f16_to_i32_r_minMag( float16_t, bint );
+    int_fast64_t f16_to_i64_r_minMag( float16_t, bint );
+    float32_t f16_to_f32( float16_t );
+    float64_t f16_to_f64( float16_t );
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # extFloat80_t f16_to_extF80( float16_t );
+    # float128_t f16_to_f128( float16_t );
+    # #endif
+    # void f16_to_extF80M( float16_t, extFloat80_t * );
+    # void f16_to_f128M( float16_t, float128_t * );
+    float16_t f16_roundToInt( float16_t, uint_fast8_t, bint );
+    float16_t f16_add( float16_t, float16_t );
+    float16_t f16_sub( float16_t, float16_t );
+    float16_t f16_mul( float16_t, float16_t );
+    float16_t f16_mulAdd( float16_t, float16_t, float16_t );
+    float16_t f16_div( float16_t, float16_t );
+    float16_t f16_rem( float16_t, float16_t );
+    float16_t f16_sqrt( float16_t );
+    bint f16_eq( float16_t, float16_t );
+    bint f16_le( float16_t, float16_t );
+    bint f16_lt( float16_t, float16_t );
+    bint f16_eq_signaling( float16_t, float16_t );
+    bint f16_le_quiet( float16_t, float16_t );
+    bint f16_lt_quiet( float16_t, float16_t );
+    bint f16_isSignalingNaN( float16_t );
+
+    # /*----------------------------------------------------------------------------
+    # | 32-bit (single-precision) floating-point operations.
+    # *----------------------------------------------------------------------------*/
+    uint_fast32_t f32_to_ui32( float32_t, uint_fast8_t, bint );
+    uint_fast64_t f32_to_ui64( float32_t, uint_fast8_t, bint );
+    int_fast32_t f32_to_i32( float32_t, uint_fast8_t, bint );
+    int_fast64_t f32_to_i64( float32_t, uint_fast8_t, bint );
+    uint_fast32_t f32_to_ui32_r_minMag( float32_t, bint );
+    uint_fast64_t f32_to_ui64_r_minMag( float32_t, bint );
+    int_fast32_t f32_to_i32_r_minMag( float32_t, bint );
+    int_fast64_t f32_to_i64_r_minMag( float32_t, bint );
+    float16_t f32_to_f16( float32_t );
+    float64_t f32_to_f64( float32_t );
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # extFloat80_t f32_to_extF80( float32_t );
+    # float128_t f32_to_f128( float32_t );
+    # #endif
+    # void f32_to_extF80M( float32_t, extFloat80_t * );
+    # void f32_to_f128M( float32_t, float128_t * );
+    float32_t f32_roundToInt( float32_t, uint_fast8_t, bint );
+    float32_t f32_add( float32_t, float32_t );
+    float32_t f32_sub( float32_t, float32_t );
+    float32_t f32_mul( float32_t, float32_t );
+    float32_t f32_mulAdd( float32_t, float32_t, float32_t );
+    float32_t f32_div( float32_t, float32_t );
+    float32_t f32_rem( float32_t, float32_t );
+    float32_t f32_sqrt( float32_t );
+    bint f32_eq( float32_t, float32_t );
+    bint f32_le( float32_t, float32_t );
+    bint f32_lt( float32_t, float32_t );
+    bint f32_eq_signaling( float32_t, float32_t );
+    bint f32_le_quiet( float32_t, float32_t );
+    bint f32_lt_quiet( float32_t, float32_t );
+    bint f32_isSignalingNaN( float32_t );
+
+    # /*----------------------------------------------------------------------------
+    # | 64-bit (double-precision) floating-point operations.
+    # *----------------------------------------------------------------------------*/
+    uint_fast32_t f64_to_ui32( float64_t, uint_fast8_t, bint );
+    uint_fast64_t f64_to_ui64( float64_t, uint_fast8_t, bint );
+    int_fast32_t f64_to_i32( float64_t, uint_fast8_t, bint );
+    int_fast64_t f64_to_i64( float64_t, uint_fast8_t, bint );
+    uint_fast32_t f64_to_ui32_r_minMag( float64_t, bint );
+    uint_fast64_t f64_to_ui64_r_minMag( float64_t, bint );
+    int_fast32_t f64_to_i32_r_minMag( float64_t, bint );
+    int_fast64_t f64_to_i64_r_minMag( float64_t, bint );
+    float16_t f64_to_f16( float64_t );
+    float32_t f64_to_f32( float64_t );
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # extFloat80_t f64_to_extF80( float64_t );
+    # float128_t f64_to_f128( float64_t );
+    # #endif
+    # void f64_to_extF80M( float64_t, extFloat80_t * );
+    # void f64_to_f128M( float64_t, float128_t * );
+    float64_t f64_roundToInt( float64_t, uint_fast8_t, bint );
+    float64_t f64_add( float64_t, float64_t );
+    float64_t f64_sub( float64_t, float64_t );
+    float64_t f64_mul( float64_t, float64_t );
+    float64_t f64_mulAdd( float64_t, float64_t, float64_t );
+    float64_t f64_div( float64_t, float64_t );
+    float64_t f64_rem( float64_t, float64_t );
+    float64_t f64_sqrt( float64_t );
+    bint f64_eq( float64_t, float64_t );
+    bint f64_le( float64_t, float64_t );
+    bint f64_lt( float64_t, float64_t );
+    bint f64_eq_signaling( float64_t, float64_t );
+    bint f64_le_quiet( float64_t, float64_t );
+    bint f64_lt_quiet( float64_t, float64_t );
+    bint f64_isSignalingNaN( float64_t );
+
+    # /*----------------------------------------------------------------------------
+    # | Rounding precision for 80-bit extended double-precision floating-point.
+    # | Valid values are 32, 64, and 80.
+    # *----------------------------------------------------------------------------*/
+    # extern THREAD_LOCAL uint_fast8_t extF80_roundingPrecision;
+
+    # /*----------------------------------------------------------------------------
+    # | 80-bit extended double-precision floating-point operations.
+    # *----------------------------------------------------------------------------*/
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # uint_fast32_t extF80_to_ui32( extFloat80_t, uint_fast8_t, bint );
+    # uint_fast64_t extF80_to_ui64( extFloat80_t, uint_fast8_t, bint );
+    # int_fast32_t extF80_to_i32( extFloat80_t, uint_fast8_t, bint );
+    # int_fast64_t extF80_to_i64( extFloat80_t, uint_fast8_t, bint );
+    # uint_fast32_t extF80_to_ui32_r_minMag( extFloat80_t, bint );
+    # uint_fast64_t extF80_to_ui64_r_minMag( extFloat80_t, bint );
+    # int_fast32_t extF80_to_i32_r_minMag( extFloat80_t, bint );
+    # int_fast64_t extF80_to_i64_r_minMag( extFloat80_t, bint );
+    # float16_t extF80_to_f16( extFloat80_t );
+    # float32_t extF80_to_f32( extFloat80_t );
+    # float64_t extF80_to_f64( extFloat80_t );
+    # float128_t extF80_to_f128( extFloat80_t );
+    # extFloat80_t extF80_roundToInt( extFloat80_t, uint_fast8_t, bint );
+    # extFloat80_t extF80_add( extFloat80_t, extFloat80_t );
+    # extFloat80_t extF80_sub( extFloat80_t, extFloat80_t );
+    # extFloat80_t extF80_mul( extFloat80_t, extFloat80_t );
+    # extFloat80_t extF80_div( extFloat80_t, extFloat80_t );
+    # extFloat80_t extF80_rem( extFloat80_t, extFloat80_t );
+    # extFloat80_t extF80_sqrt( extFloat80_t );
+    # bint extF80_eq( extFloat80_t, extFloat80_t );
+    # bint extF80_le( extFloat80_t, extFloat80_t );
+    # bint extF80_lt( extFloat80_t, extFloat80_t );
+    # bint extF80_eq_signaling( extFloat80_t, extFloat80_t );
+    # bint extF80_le_quiet( extFloat80_t, extFloat80_t );
+    # bint extF80_lt_quiet( extFloat80_t, extFloat80_t );
+    # bint extF80_isSignalingNaN( extFloat80_t );
+    # #endif
+    # uint_fast32_t extF80M_to_ui32( const extFloat80_t *, uint_fast8_t, bint );
+    # uint_fast64_t extF80M_to_ui64( const extFloat80_t *, uint_fast8_t, bint );
+    # int_fast32_t extF80M_to_i32( const extFloat80_t *, uint_fast8_t, bint );
+    # int_fast64_t extF80M_to_i64( const extFloat80_t *, uint_fast8_t, bint );
+    # uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *, bint );
+    # uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *, bint );
+    # int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *, bint );
+    # int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *, bint );
+    # float16_t extF80M_to_f16( const extFloat80_t * );
+    # float32_t extF80M_to_f32( const extFloat80_t * );
+    # float64_t extF80M_to_f64( const extFloat80_t * );
+    # void extF80M_to_f128M( const extFloat80_t *, float128_t * );
+    # void
+    #  extF80M_roundToInt(
+    #      const extFloat80_t *, uint_fast8_t, bint, extFloat80_t * );
+    # void extF80M_add( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
+    # void extF80M_sub( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
+    # void extF80M_mul( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
+    # void extF80M_div( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
+    # void extF80M_rem( const extFloat80_t *, const extFloat80_t *, extFloat80_t * );
+    # void extF80M_sqrt( const extFloat80_t *, extFloat80_t * );
+    # bint extF80M_eq( const extFloat80_t *, const extFloat80_t * );
+    # bint extF80M_le( const extFloat80_t *, const extFloat80_t * );
+    # bint extF80M_lt( const extFloat80_t *, const extFloat80_t * );
+    # bint extF80M_eq_signaling( const extFloat80_t *, const extFloat80_t * );
+    # bint extF80M_le_quiet( const extFloat80_t *, const extFloat80_t * );
+    # bint extF80M_lt_quiet( const extFloat80_t *, const extFloat80_t * );
+    # bint extF80M_isSignalingNaN( const extFloat80_t * );
+
+    # /*----------------------------------------------------------------------------
+    # | 128-bit (quadruple-precision) floating-point operations.
+    # *----------------------------------------------------------------------------*/
+    # #ifdef SOFTFLOAT_FAST_INT64
+    # uint_fast32_t f128_to_ui32( float128_t, uint_fast8_t, bint );
+    # uint_fast64_t f128_to_ui64( float128_t, uint_fast8_t, bint );
+    # int_fast32_t f128_to_i32( float128_t, uint_fast8_t, bint );
+    # int_fast64_t f128_to_i64( float128_t, uint_fast8_t, bint );
+    # uint_fast32_t f128_to_ui32_r_minMag( float128_t, bint );
+    # uint_fast64_t f128_to_ui64_r_minMag( float128_t, bint );
+    # int_fast32_t f128_to_i32_r_minMag( float128_t, bint );
+    # int_fast64_t f128_to_i64_r_minMag( float128_t, bint );
+    # float16_t f128_to_f16( float128_t );
+    # float32_t f128_to_f32( float128_t );
+    # float64_t f128_to_f64( float128_t );
+    # extFloat80_t f128_to_extF80( float128_t );
+    # float128_t f128_roundToInt( float128_t, uint_fast8_t, bint );
+    # float128_t f128_add( float128_t, float128_t );
+    # float128_t f128_sub( float128_t, float128_t );
+    # float128_t f128_mul( float128_t, float128_t );
+    # float128_t f128_mulAdd( float128_t, float128_t, float128_t );
+    # float128_t f128_div( float128_t, float128_t );
+    # float128_t f128_rem( float128_t, float128_t );
+    # float128_t f128_sqrt( float128_t );
+    # bint f128_eq( float128_t, float128_t );
+    # bint f128_le( float128_t, float128_t );
+    # bint f128_lt( float128_t, float128_t );
+    # bint f128_eq_signaling( float128_t, float128_t );
+    # bint f128_le_quiet( float128_t, float128_t );
+    # bint f128_lt_quiet( float128_t, float128_t );
+    # bint f128_isSignalingNaN( float128_t );
+    # #endif
+    # uint_fast32_t f128M_to_ui32( const float128_t *, uint_fast8_t, bint );
+    # uint_fast64_t f128M_to_ui64( const float128_t *, uint_fast8_t, bint );
+    # int_fast32_t f128M_to_i32( const float128_t *, uint_fast8_t, bint );
+    # int_fast64_t f128M_to_i64( const float128_t *, uint_fast8_t, bint );
+    # uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *, bint );
+    # uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *, bint );
+    # int_fast32_t f128M_to_i32_r_minMag( const float128_t *, bint );
+    # int_fast64_t f128M_to_i64_r_minMag( const float128_t *, bint );
+    # float16_t f128M_to_f16( const float128_t * );
+    # float32_t f128M_to_f32( const float128_t * );
+    # float64_t f128M_to_f64( const float128_t * );
+    # void f128M_to_extF80M( const float128_t *, extFloat80_t * );
+    # void f128M_roundToInt( const float128_t *, uint_fast8_t, bint, float128_t * );
+    # void f128M_add( const float128_t *, const float128_t *, float128_t * );
+    # void f128M_sub( const float128_t *, const float128_t *, float128_t * );
+    # void f128M_mul( const float128_t *, const float128_t *, float128_t * );
+    # void
+    #  f128M_mulAdd(
+    #      const float128_t *, const float128_t *, const float128_t *, float128_t *
+    #  );
+    # void f128M_div( const float128_t *, const float128_t *, float128_t * );
+    # void f128M_rem( const float128_t *, const float128_t *, float128_t * );
+    # void f128M_sqrt( const float128_t *, float128_t * );
+    # bint f128M_eq( const float128_t *, const float128_t * );
+    # bint f128M_le( const float128_t *, const float128_t * );
+    # bint f128M_lt( const float128_t *, const float128_t * );
+    # bint f128M_eq_signaling( const float128_t *, const float128_t * );
+    # bint f128M_le_quiet( const float128_t *, const float128_t * );
+    # bint f128M_lt_quiet( const float128_t *, const float128_t * );
+    # bint f128M_isSignalingNaN( const float128_t * );
diff --git a/sfpy/float.pyx b/sfpy/float.pyx
new file mode 100644 (file)
index 0000000..261226c
--- /dev/null
@@ -0,0 +1,951 @@
+from libc.stdint cimport *
+cimport cfloat
+
+
+# low-level access to rounding modes
+
+ROUND_NEAREST_EVEN = cfloat.softfloat_round_near_even
+ROUND_TO_ZERO = cfloat.softfloat_round_minMag
+ROUND_DOWN = cfloat.softfloat_round_min
+ROUND_UP = cfloat.softfloat_round_max
+ROUND_NEAREST_AWAY = cfloat.softfloat_round_near_maxMag
+
+cpdef uint_fast8_t round_get_mode():
+    return cfloat.softfloat_roundingMode
+
+cpdef void round_set_mode(uint_fast8_t mode):
+    cfloat.softfloat_roundingMode = mode
+
+cpdef bint round_is_nearest_even():
+    return cfloat.softfloat_roundingMode == cfloat.softfloat_round_near_even
+
+cpdef void round_set_nearest_even():
+    cfloat.softfloat_roundingMode = cfloat.softfloat_round_near_even
+
+cpdef bint round_is_to_zero():
+    return cfloat.softfloat_roundingMode == cfloat.softfloat_round_minMag
+
+cpdef void round_set_to_zero():
+    cfloat.softfloat_roundingMode = cfloat.softfloat_round_minMag
+
+cpdef bint round_is_down():
+    return cfloat.softfloat_roundingMode == cfloat.softfloat_round_min
+
+cpdef void round_set_down():
+    cfloat.softfloat_roundingMode = cfloat.softfloat_round_min
+
+cpdef bint round_is_up():
+    return cfloat.softfloat_roundingMode == cfloat.softfloat_round_max
+
+cpdef void round_set_up():
+    cfloat.softfloat_roundingMode = cfloat.softfloat_round_max
+
+cpdef bint round_is_nearest_away():
+    return cfloat.softfloat_roundingMode == cfloat.softfloat_round_near_maxMag
+
+cpdef void round_set_nearest_away():
+    cfloat.softfloat_roundingMode = cfloat.softfloat_round_near_maxMag
+
+
+# low-level access to exception flags
+
+FLAG_INEXACT = cfloat.softfloat_flag_inexact
+FLAG_UNDERFLOW = cfloat.softfloat_flag_underflow
+FLAG_OVERFLOW = cfloat.softfloat_flag_overflow
+FLAG_INFINITE = cfloat.softfloat_flag_infinite
+FLAG_INVALID = cfloat.softfloat_flag_invalid
+
+cpdef uint_fast8_t flag_get():
+    return cfloat.softfloat_exceptionFlags
+
+cpdef void flag_set(uint_fast8_t flags):
+    cfloat.softfloat_exceptionFlags = flags
+
+cpdef void flag_reset():
+    cfloat.softfloat_exceptionFlags = 0
+
+cpdef bint flag_get_inexact():
+    return (cfloat.softfloat_exceptionFlags & cfloat.softfloat_flag_inexact) != 0
+
+cpdef void flag_raise_inexact():
+    cfloat.softfloat_raiseFlags(cfloat.softfloat_flag_inexact)
+
+cpdef void flag_clear_inexact():
+    cfloat.softfloat_exceptionFlags &= ~cfloat.softfloat_flag_inexact
+
+cpdef bint flag_get_underflow():
+    return (cfloat.softfloat_exceptionFlags & cfloat.softfloat_flag_underflow) != 0
+
+cpdef void flag_raise_underflow():
+    cfloat.softfloat_raiseFlags(cfloat.softfloat_flag_underflow)
+
+cpdef void flag_clear_underflow():
+    cfloat.softfloat_exceptionFlags &= ~cfloat.softfloat_flag_underflow
+
+cpdef bint flag_get_overflow():
+    return (cfloat.softfloat_exceptionFlags & cfloat.softfloat_flag_overflow) != 0
+
+cpdef void flag_raise_overflow():
+    cfloat.softfloat_raiseFlags(cfloat.softfloat_flag_overflow)
+
+cpdef void flag_clear_overflow():
+    cfloat.softfloat_exceptionFlags &= ~cfloat.softfloat_flag_overflow
+
+cpdef bint flag_get_infinite():
+    return (cfloat.softfloat_exceptionFlags & cfloat.softfloat_flag_infinite) != 0
+
+cpdef void flag_raise_infinite():
+    cfloat.softfloat_raiseFlags(cfloat.softfloat_flag_infinite)
+
+cpdef void flag_clear_infinite():
+    cfloat.softfloat_exceptionFlags &= ~cfloat.softfloat_flag_infinite
+
+cpdef bint flag_get_invalid():
+    return (cfloat.softfloat_exceptionFlags & cfloat.softfloat_flag_invalid) != 0
+
+cpdef void flag_raise_invalid():
+    cfloat.softfloat_raiseFlags(cfloat.softfloat_flag_invalid)
+
+cpdef void flag_clear_invalid():
+    cfloat.softfloat_exceptionFlags &= ~cfloat.softfloat_flag_invalid
+
+
+cdef class Float16:
+
+    # the wrapped float value
+    cdef cfloat.float16_t _c_float
+
+    # factory function constructors that bypass __init__
+
+    @staticmethod
+    cdef Float16 from_c_float(cfloat.float16_t f):
+        """Factory function to create a Float16 object directly from
+        a C float16_t.
+        """
+        cdef Float16 obj = Float16.__new__(Float16)
+        obj._c_float = f
+        return obj
+
+    @staticmethod
+    def from_bits(uint16_t value):
+        """Factory function to create a Float16 object from a bit pattern
+        represented as an integer.
+        """
+        cdef Float16 obj = Float16.__new__(Float16)
+        obj._c_float.v = value
+        return obj
+
+    @staticmethod
+    def from_double(double value):
+        """Factory function to create a Float16 object from a double.
+        """
+        cdef Float16 obj = Float16.__new__(Float16)
+        cdef cfloat.ui64_double ud
+        cdef cfloat.float64_t d
+
+        ud.d = value
+        d.v = ud.u
+        obj._c_float = cfloat.f64_to_f16(d)
+
+        return obj
+
+    # convenience interface for use inside Python
+
+    def __init__(self, value):
+        cdef cfloat.ui64_double ud
+        cdef cfloat.float64_t d
+
+        if isinstance(value, int):
+            self._c_float.v = value
+        else:
+            ud.d = float(value)
+            d.v = ud.u
+            self._c_float = cfloat.f64_to_f16(d)
+
+    def __float__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = cfloat.f16_to_f64(self._c_float).v
+        return ud.d
+
+    def __int__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = cfloat.f16_to_f64(self._c_float).v
+        return int(ud.d)
+
+    def __str__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = cfloat.f16_to_f64(self._c_float).v
+        return repr(ud.d)
+
+    def __repr__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = cfloat.f16_to_f64(self._c_float).v
+        return 'Float16(' + repr(ud.d) + ')'
+
+    cpdef uint16_t get_bits(self):
+        return self._c_float.v
+    bits = property(get_bits)
+
+    # arithmetic
+
+    cpdef Float16 round_to(self, uint_fast8_t rm, bint exact):
+        cdef cfloat.float16_t f = cfloat.f16_roundToInt(self._c_float, rm, exact)
+        return Float16.from_c_float(f)
+
+    cpdef Float16 round(self):
+        cdef cfloat.float16_t f = cfloat.f16_roundToInt(self._c_float, cfloat.softfloat_roundingMode, True)
+        return Float16.from_c_float(f)
+
+    def __round__(self):
+        return self.round()
+
+    cpdef Float16 add(self, Float16 other):
+        cdef cfloat.float16_t f = cfloat.f16_add(self._c_float, other._c_float)
+        return Float16.from_c_float(f)
+
+    def __add__(self, Float16 other):
+        return self.add(other)
+
+    cpdef Float16 sub(self, Float16 other):
+        cdef cfloat.float16_t f = cfloat.f16_sub(self._c_float, other._c_float)
+        return Float16.from_c_float(f)
+
+    def __sub__(self, Float16 other):
+        return self.sub(other)
+
+    cpdef Float16 mul(self, Float16 other):
+        cdef cfloat.float16_t f = cfloat.f16_mul(self._c_float, other._c_float)
+        return Float16.from_c_float(f)
+
+    def __mul__(self, Float16 other):
+        return self.mul(other)
+
+    cpdef Float16 fma(self, Float16 a2, Float16 a3):
+        cdef cfloat.float16_t f = cfloat.f16_mulAdd(self._c_float, a2._c_float, a3._c_float)
+        return Float16.from_c_float(f)
+
+    cpdef Float16 qma(self, Float16 a1, Float16 a2):
+        cdef cfloat.float16_t f = cfloat.f16_mulAdd(a1._c_float, a2._c_float, self._c_float)
+        return Float16.from_c_float(f)
+
+    cpdef Float16 div(self, Float16 other):
+        cdef cfloat.float16_t f = cfloat.f16_div(self._c_float, other._c_float)
+        return Float16.from_c_float(f)
+
+    def __truediv__(self, Float16 other):
+        return self.div(other)
+
+    cpdef Float16 rem(self, Float16 other):
+        cdef cfloat.float16_t f = cfloat.f16_rem(self._c_float, other._c_float)
+        return Float16.from_c_float(f)
+
+    cpdef Float16 sqrt(self):
+        cdef cfloat.float16_t f = cfloat.f16_sqrt(self._c_float)
+        return Float16.from_c_float(f)
+
+    # in-place arithmetic
+
+    cpdef void iround_to(self, uint_fast8_t rm, bint exact):
+        self._c_float = cfloat.f16_roundToInt(self._c_float, rm, exact)
+
+    cpdef void iround(self):
+        self._c_float = cfloat.f16_roundToInt(self._c_float, cfloat.softfloat_roundingMode, True)
+
+    cpdef void iadd(self, Float16 other):
+        self._c_float = cfloat.f16_add(self._c_float, other._c_float)
+
+    def __iadd__(self, Float16 other):
+        self.iadd(other)
+        return self
+
+    cpdef void isub(self, Float16 other):
+        self._c_float = cfloat.f16_sub(self._c_float, other._c_float)
+
+    def __isub__(self, Float16 other):
+        self.isub(other)
+        return self
+
+    cpdef void imul(self, Float16 other):
+        self._c_float = cfloat.f16_mul(self._c_float, other._c_float)
+
+    def __imul__(self, Float16 other):
+        self.imul(other)
+        return self
+
+    cpdef void ifma(self, Float16 a2, Float16 a3):
+        self._c_float = cfloat.f16_mulAdd(self._c_float, a2._c_float, a3._c_float)
+
+    cpdef void iqma(self, Float16 a1, Float16 a2):
+        self._c_float = cfloat.f16_mulAdd(a1._c_float, a2._c_float, self._c_float)
+
+    cpdef void idiv(self, Float16 other):
+        self._c_float = cfloat.f16_div(self._c_float, other._c_float)
+
+    def __itruediv__(self, Float16 other):
+        self.idiv(other)
+        return self
+
+    cpdef void irem(self, Float16 other):
+        self._c_float = cfloat.f16_rem(self._c_float, other._c_float)
+
+    cpdef void isqrt(self):
+        self._c_float = cfloat.f16_sqrt(self._c_float)
+
+    # comparison
+
+    cpdef bint eq(self, Float16 other):
+        return cfloat.f16_eq(self._c_float, other._c_float)
+
+    cpdef bint le(self, Float16 other):
+        return cfloat.f16_le(self._c_float, other._c_float)
+
+    cpdef bint lt(self, Float16 other):
+        return cfloat.f16_lt(self._c_float, other._c_float)
+
+    def __lt__(self, Float16 other):
+        return self.lt(other)
+
+    def __le__(self, Float16 other):
+        return self.le(other)
+
+    def __eq__(self, Float16 other):
+        return self.eq(other)
+
+    def __ne__(self, Float16 other):
+        return not self.eq(other)
+
+    def __ge__(self, Float16 other):
+        return other.le(self)
+
+    def __gt__(self, Float16 other):
+        return other.lt(self)
+
+    # conversion to other float types
+
+    cpdef Float32 to_f32(self):
+        cdef cfloat.float32_t f = cfloat.f16_to_f32(self._c_float)
+        return Float32.from_c_float(f)
+
+    cpdef Float64 to_f64(self):
+        cdef cfloat.float64_t f = cfloat.f16_to_f64(self._c_float)
+        return Float64.from_c_float(f)
+
+
+# external, non-method arithmetic
+
+cpdef Float16 f16_round_to(Float16 a1, uint_fast8_t rm, bint exact):
+    cdef cfloat.float16_t f = cfloat.f16_roundToInt(a1._c_float, rm, exact)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_round(Float16 a1):
+    cdef cfloat.float16_t f = cfloat.f16_roundToInt(a1._c_float, cfloat.softfloat_roundingMode, True)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_add(Float16 a1, Float16 a2):
+    cdef cfloat.float16_t f = cfloat.f16_add(a1._c_float, a2._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_sub(Float16 a1, Float16 a2):
+    cdef cfloat.float16_t f = cfloat.f16_sub(a1._c_float, a2._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_mul(Float16 a1, Float16 a2):
+    cdef cfloat.float16_t f = cfloat.f16_mul(a1._c_float, a2._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_fma(Float16 a1, Float16 a2, Float16 a3):
+    cdef cfloat.float16_t f = cfloat.f16_mulAdd(a1._c_float, a2._c_float, a3._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_qma(Float16 a3, Float16 a1, Float16 a2):
+    cdef cfloat.float16_t f = cfloat.f16_mulAdd(a1._c_float, a2._c_float, a3._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_div(Float16 a1, Float16 a2):
+    cdef cfloat.float16_t f = cfloat.f16_div(a1._c_float, a2._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_rem(Float16 a1, Float16 a2):
+    cdef cfloat.float16_t f = cfloat.f16_rem(a1._c_float, a2._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_sqrt(Float16 a1):
+    cdef cfloat.float16_t f = cfloat.f16_sqrt(a1._c_float)
+    return Float16.from_c_float(f)
+
+cpdef bint f16_eq(Float16 a1, Float16 a2):
+    return cfloat.f16_eq(a1._c_float, a2._c_float)
+
+cpdef bint f16_le(Float16 a1, Float16 a2):
+    return cfloat.f16_le(a1._c_float, a2._c_float)
+
+cpdef bint f16_lt(Float16 a1, Float16 a2):
+    return cfloat.f16_lt(a1._c_float, a2._c_float)
+
+cpdef Float32 f16_to_f32(Float16 a1):
+    cdef cfloat.float32_t f = cfloat.f16_to_f32(a1._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float64 f16_to_f64(Float16 a1):
+    cdef cfloat.float64_t f = cfloat.f16_to_f64(a1._c_float)
+    return Float64.from_c_float(f)
+
+
+cdef class Float32:
+
+    # the wrapped float value
+    cdef cfloat.float32_t _c_float
+
+    # factory function constructors that bypass __init__
+
+    @staticmethod
+    cdef Float32 from_c_float(cfloat.float32_t f):
+        """Factory function to create a Float32 object directly from
+        a C float32_t.
+        """
+        cdef Float32 obj = Float32.__new__(Float32)
+        obj._c_float = f
+        return obj
+
+    @staticmethod
+    def from_bits(uint32_t value):
+        """Factory function to create a Float32 object from a bit pattern
+        represented as an integer.
+        """
+        cdef Float32 obj = Float32.__new__(Float32)
+        obj._c_float.v = value
+        return obj
+
+    @staticmethod
+    def from_double(double value):
+        """Factory function to create a Float32 object from a double.
+        """
+        cdef Float32 obj = Float32.__new__(Float32)
+        cdef cfloat.ui64_double ud
+        cdef cfloat.float64_t d
+
+        ud.d = value
+        d.v = ud.u
+        obj._c_float = cfloat.f64_to_f32(d)
+
+        return obj
+
+    # convenience interface for use inside Python
+
+    def __init__(self, value):
+        cdef cfloat.ui64_double ud
+        cdef cfloat.float64_t d
+
+        if isinstance(value, int):
+            self._c_float.v = value
+        else:
+            ud.d = float(value)
+            d.v = ud.u
+            self._c_float = cfloat.f64_to_f32(d)
+
+    def __float__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = cfloat.f32_to_f64(self._c_float).v
+        return ud.d
+
+    def __int__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = cfloat.f32_to_f64(self._c_float).v
+        return int(ud.d)
+
+    def __str__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = cfloat.f32_to_f64(self._c_float).v
+        return repr(ud.d)
+
+    def __repr__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = cfloat.f32_to_f64(self._c_float).v
+        return 'Float32(' + repr(ud.d) + ')'
+
+    cpdef uint32_t get_bits(self):
+        return self._c_float.v
+    bits = property(get_bits)
+
+    # arithmetic
+
+    cpdef Float32 round_to(self, uint_fast8_t rm, bint exact):
+        cdef cfloat.float32_t f = cfloat.f32_roundToInt(self._c_float, rm, exact)
+        return Float32.from_c_float(f)
+
+    cpdef Float32 round(self):
+        cdef cfloat.float32_t f = cfloat.f32_roundToInt(self._c_float, cfloat.softfloat_roundingMode, True)
+        return Float32.from_c_float(f)
+
+    def __round__(self):
+        return self.round()
+
+    cpdef Float32 add(self, Float32 other):
+        cdef cfloat.float32_t f = cfloat.f32_add(self._c_float, other._c_float)
+        return Float32.from_c_float(f)
+
+    def __add__(self, Float32 other):
+        return self.add(other)
+
+    cpdef Float32 sub(self, Float32 other):
+        cdef cfloat.float32_t f = cfloat.f32_sub(self._c_float, other._c_float)
+        return Float32.from_c_float(f)
+
+    def __sub__(self, Float32 other):
+        return self.sub(other)
+
+    cpdef Float32 mul(self, Float32 other):
+        cdef cfloat.float32_t f = cfloat.f32_mul(self._c_float, other._c_float)
+        return Float32.from_c_float(f)
+
+    def __mul__(self, Float32 other):
+        return self.mul(other)
+
+    cpdef Float32 fma(self, Float32 a2, Float32 a3):
+        cdef cfloat.float32_t f = cfloat.f32_mulAdd(self._c_float, a2._c_float, a3._c_float)
+        return Float32.from_c_float(f)
+
+    cpdef Float32 qma(self, Float32 a1, Float32 a2):
+        cdef cfloat.float32_t f = cfloat.f32_mulAdd(a1._c_float, a2._c_float, self._c_float)
+        return Float32.from_c_float(f)
+
+    cpdef Float32 div(self, Float32 other):
+        cdef cfloat.float32_t f = cfloat.f32_div(self._c_float, other._c_float)
+        return Float32.from_c_float(f)
+
+    def __truediv__(self, Float32 other):
+        return self.div(other)
+
+    cpdef Float32 rem(self, Float32 other):
+        cdef cfloat.float32_t f = cfloat.f32_rem(self._c_float, other._c_float)
+        return Float32.from_c_float(f)
+
+    cpdef Float32 sqrt(self):
+        cdef cfloat.float32_t f = cfloat.f32_sqrt(self._c_float)
+        return Float32.from_c_float(f)
+
+    # in-place arithmetic
+
+    cpdef void iround_to(self, uint_fast8_t rm, bint exact):
+        self._c_float = cfloat.f32_roundToInt(self._c_float, rm, exact)
+
+    cpdef void iround(self):
+        self._c_float = cfloat.f32_roundToInt(self._c_float, cfloat.softfloat_roundingMode, True)
+
+    cpdef void iadd(self, Float32 other):
+        self._c_float = cfloat.f32_add(self._c_float, other._c_float)
+
+    def __iadd__(self, Float32 other):
+        self.iadd(other)
+        return self
+
+    cpdef void isub(self, Float32 other):
+        self._c_float = cfloat.f32_sub(self._c_float, other._c_float)
+
+    def __isub__(self, Float32 other):
+        self.isub(other)
+        return self
+
+    cpdef void imul(self, Float32 other):
+        self._c_float = cfloat.f32_mul(self._c_float, other._c_float)
+
+    def __imul__(self, Float32 other):
+        self.imul(other)
+        return self
+
+    cpdef void ifma(self, Float32 a2, Float32 a3):
+        self._c_float = cfloat.f32_mulAdd(self._c_float, a2._c_float, a3._c_float)
+
+    cpdef void iqma(self, Float32 a1, Float32 a2):
+        self._c_float = cfloat.f32_mulAdd(a1._c_float, a2._c_float, self._c_float)
+
+    cpdef void idiv(self, Float32 other):
+        self._c_float = cfloat.f32_div(self._c_float, other._c_float)
+
+    def __itruediv__(self, Float32 other):
+        self.idiv(other)
+        return self
+
+    cpdef void irem(self, Float32 other):
+        self._c_float = cfloat.f32_rem(self._c_float, other._c_float)
+
+    cpdef void isqrt(self):
+        self._c_float = cfloat.f32_sqrt(self._c_float)
+
+    # comparison
+
+    cpdef bint eq(self, Float32 other):
+        return cfloat.f32_eq(self._c_float, other._c_float)
+
+    cpdef bint le(self, Float32 other):
+        return cfloat.f32_le(self._c_float, other._c_float)
+
+    cpdef bint lt(self, Float32 other):
+        return cfloat.f32_lt(self._c_float, other._c_float)
+
+    def __lt__(self, Float32 other):
+        return self.lt(other)
+
+    def __le__(self, Float32 other):
+        return self.le(other)
+
+    def __eq__(self, Float32 other):
+        return self.eq(other)
+
+    def __ne__(self, Float32 other):
+        return not self.eq(other)
+
+    def __ge__(self, Float32 other):
+        return other.le(self)
+
+    def __gt__(self, Float32 other):
+        return other.lt(self)
+
+    # conversion to other float types
+
+    cpdef Float16 to_f16(self):
+        cdef cfloat.float16_t f = cfloat.f32_to_f16(self._c_float)
+        return Float16.from_c_float(f)
+
+    cpdef Float64 to_f64(self):
+        cdef cfloat.float64_t f = cfloat.f32_to_f64(self._c_float)
+        return Float64.from_c_float(f)
+
+
+# external, non-method arithmetic
+
+cpdef Float32 f32_round_to(Float32 a1, uint_fast8_t rm, bint exact):
+    cdef cfloat.float32_t f = cfloat.f32_roundToInt(a1._c_float, rm, exact)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_round(Float32 a1):
+    cdef cfloat.float32_t f = cfloat.f32_roundToInt(a1._c_float, cfloat.softfloat_roundingMode, True)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_add(Float32 a1, Float32 a2):
+    cdef cfloat.float32_t f = cfloat.f32_add(a1._c_float, a2._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_sub(Float32 a1, Float32 a2):
+    cdef cfloat.float32_t f = cfloat.f32_sub(a1._c_float, a2._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_mul(Float32 a1, Float32 a2):
+    cdef cfloat.float32_t f = cfloat.f32_mul(a1._c_float, a2._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_fma(Float32 a1, Float32 a2, Float32 a3):
+    cdef cfloat.float32_t f = cfloat.f32_mulAdd(a1._c_float, a2._c_float, a3._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_qma(Float32 a3, Float32 a1, Float32 a2):
+    cdef cfloat.float32_t f = cfloat.f32_mulAdd(a1._c_float, a2._c_float, a3._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_div(Float32 a1, Float32 a2):
+    cdef cfloat.float32_t f = cfloat.f32_div(a1._c_float, a2._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_rem(Float32 a1, Float32 a2):
+    cdef cfloat.float32_t f = cfloat.f32_rem(a1._c_float, a2._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_sqrt(Float32 a1):
+    cdef cfloat.float32_t f = cfloat.f32_sqrt(a1._c_float)
+    return Float32.from_c_float(f)
+
+cpdef bint f32_eq(Float32 a1, Float32 a2):
+    return cfloat.f32_eq(a1._c_float, a2._c_float)
+
+cpdef bint f32_le(Float32 a1, Float32 a2):
+    return cfloat.f32_le(a1._c_float, a2._c_float)
+
+cpdef bint f32_lt(Float32 a1, Float32 a2):
+    return cfloat.f32_lt(a1._c_float, a2._c_float)
+
+cpdef Float16 f32_to_f16(Float32 a1):
+    cdef cfloat.float16_t f = cfloat.f32_to_f16(a1._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float64 f32_to_f64(Float32 a1):
+    cdef cfloat.float64_t f = cfloat.f32_to_f64(a1._c_float)
+    return Float64.from_c_float(f)
+
+
+cdef class Float64:
+
+    # the wrapped float value
+    cdef cfloat.float64_t _c_float
+
+    # factory function constructors that bypass __init__
+
+    @staticmethod
+    cdef Float64 from_c_float(cfloat.float64_t f):
+        """Factory function to create a Float64 object directly from
+        a C float64_t.
+        """
+        cdef Float64 obj = Float64.__new__(Float64)
+        obj._c_float = f
+        return obj
+
+    @staticmethod
+    def from_bits(uint64_t value):
+        """Factory function to create a Float64 object from a bit pattern
+        represented as an integer.
+        """
+        cdef Float64 obj = Float64.__new__(Float64)
+        obj._c_float.v = value
+        return obj
+
+    @staticmethod
+    def from_double(double value):
+        """Factory function to create a Float64 object from a double.
+        """
+        cdef Float64 obj = Float64.__new__(Float64)
+        cdef cfloat.ui64_double ud
+        cdef cfloat.float64_t d
+
+        ud.d = value
+        obj._c_float.v = ud.u
+
+        return obj
+
+    # convenience interface for use inside Python
+
+    def __init__(self, value):
+        cdef cfloat.ui64_double ud
+        cdef cfloat.float64_t d
+
+        if isinstance(value, int):
+            self._c_float.v = value
+        else:
+            ud.d = float(value)
+            self._c_float.v = ud.u
+
+    def __float__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = self._c_float.v
+        return ud.d
+
+    def __int__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = self._c_float.v
+        return int(ud.d)
+
+    def __str__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = self._c_float.v
+        return repr(ud.d)
+
+    def __repr__(self):
+        cdef cfloat.ui64_double ud
+        ud.u = self._c_float.v
+        return 'Float64(' + repr(ud.d) + ')'
+
+    cpdef uint64_t get_bits(self):
+        return self._c_float.v
+    bits = property(get_bits)
+
+    # arithmetic
+
+    cpdef Float64 round_to(self, uint_fast8_t rm, bint exact):
+        cdef cfloat.float64_t f = cfloat.f64_roundToInt(self._c_float, rm, exact)
+        return Float64.from_c_float(f)
+
+    cpdef Float64 round(self):
+        cdef cfloat.float64_t f = cfloat.f64_roundToInt(self._c_float, cfloat.softfloat_roundingMode, True)
+        return Float64.from_c_float(f)
+
+    def __round__(self):
+        return self.round()
+
+    cpdef Float64 add(self, Float64 other):
+        cdef cfloat.float64_t f = cfloat.f64_add(self._c_float, other._c_float)
+        return Float64.from_c_float(f)
+
+    def __add__(self, Float64 other):
+        return self.add(other)
+
+    cpdef Float64 sub(self, Float64 other):
+        cdef cfloat.float64_t f = cfloat.f64_sub(self._c_float, other._c_float)
+        return Float64.from_c_float(f)
+
+    def __sub__(self, Float64 other):
+        return self.sub(other)
+
+    cpdef Float64 mul(self, Float64 other):
+        cdef cfloat.float64_t f = cfloat.f64_mul(self._c_float, other._c_float)
+        return Float64.from_c_float(f)
+
+    def __mul__(self, Float64 other):
+        return self.mul(other)
+
+    cpdef Float64 fma(self, Float64 a2, Float64 a3):
+        cdef cfloat.float64_t f = cfloat.f64_mulAdd(self._c_float, a2._c_float, a3._c_float)
+        return Float64.from_c_float(f)
+
+    cpdef Float64 qma(self, Float64 a1, Float64 a2):
+        cdef cfloat.float64_t f = cfloat.f64_mulAdd(a1._c_float, a2._c_float, self._c_float)
+        return Float64.from_c_float(f)
+
+    cpdef Float64 div(self, Float64 other):
+        cdef cfloat.float64_t f = cfloat.f64_div(self._c_float, other._c_float)
+        return Float64.from_c_float(f)
+
+    def __truediv__(self, Float64 other):
+        return self.div(other)
+
+    cpdef Float64 rem(self, Float64 other):
+        cdef cfloat.float64_t f = cfloat.f64_rem(self._c_float, other._c_float)
+        return Float64.from_c_float(f)
+
+    cpdef Float64 sqrt(self):
+        cdef cfloat.float64_t f = cfloat.f64_sqrt(self._c_float)
+        return Float64.from_c_float(f)
+
+    # in-place arithmetic
+
+    cpdef void iround_to(self, uint_fast8_t rm, bint exact):
+        self._c_float = cfloat.f64_roundToInt(self._c_float, rm, exact)
+
+    cpdef void iround(self):
+        self._c_float = cfloat.f64_roundToInt(self._c_float, cfloat.softfloat_roundingMode, True)
+
+    cpdef void iadd(self, Float64 other):
+        self._c_float = cfloat.f64_add(self._c_float, other._c_float)
+
+    def __iadd__(self, Float64 other):
+        self.iadd(other)
+        return self
+
+    cpdef void isub(self, Float64 other):
+        self._c_float = cfloat.f64_sub(self._c_float, other._c_float)
+
+    def __isub__(self, Float64 other):
+        self.isub(other)
+        return self
+
+    cpdef void imul(self, Float64 other):
+        self._c_float = cfloat.f64_mul(self._c_float, other._c_float)
+
+    def __imul__(self, Float64 other):
+        self.imul(other)
+        return self
+
+    cpdef void ifma(self, Float64 a2, Float64 a3):
+        self._c_float = cfloat.f64_mulAdd(self._c_float, a2._c_float, a3._c_float)
+
+    cpdef void iqma(self, Float64 a1, Float64 a2):
+        self._c_float = cfloat.f64_mulAdd(a1._c_float, a2._c_float, self._c_float)
+
+    cpdef void idiv(self, Float64 other):
+        self._c_float = cfloat.f64_div(self._c_float, other._c_float)
+
+    def __itruediv__(self, Float64 other):
+        self.idiv(other)
+        return self
+
+    cpdef void irem(self, Float64 other):
+        self._c_float = cfloat.f64_rem(self._c_float, other._c_float)
+
+    cpdef void isqrt(self):
+        self._c_float = cfloat.f64_sqrt(self._c_float)
+
+    # comparison
+
+    cpdef bint eq(self, Float64 other):
+        return cfloat.f64_eq(self._c_float, other._c_float)
+
+    cpdef bint le(self, Float64 other):
+        return cfloat.f64_le(self._c_float, other._c_float)
+
+    cpdef bint lt(self, Float64 other):
+        return cfloat.f64_lt(self._c_float, other._c_float)
+
+    def __lt__(self, Float64 other):
+        return self.lt(other)
+
+    def __le__(self, Float64 other):
+        return self.le(other)
+
+    def __eq__(self, Float64 other):
+        return self.eq(other)
+
+    def __ne__(self, Float64 other):
+        return not self.eq(other)
+
+    def __ge__(self, Float64 other):
+        return other.le(self)
+
+    def __gt__(self, Float64 other):
+        return other.lt(self)
+
+    # conversion to other float types
+
+    cpdef Float16 to_f16(self):
+        cdef cfloat.float16_t f = cfloat.f64_to_f16(self._c_float)
+        return Float16.from_c_float(f)
+
+    cpdef Float32 to_f32(self):
+        cdef cfloat.float32_t f = cfloat.f64_to_f32(self._c_float)
+        return Float32.from_c_float(f)
+
+
+# external, non-method arithmetic
+
+cpdef Float64 f64_round_to(Float64 a1, uint_fast8_t rm, bint exact):
+    cdef cfloat.float64_t f = cfloat.f64_roundToInt(a1._c_float, rm, exact)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_round(Float64 a1):
+    cdef cfloat.float64_t f = cfloat.f64_roundToInt(a1._c_float, cfloat.softfloat_roundingMode, True)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_add(Float64 a1, Float64 a2):
+    cdef cfloat.float64_t f = cfloat.f64_add(a1._c_float, a2._c_float)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_sub(Float64 a1, Float64 a2):
+    cdef cfloat.float64_t f = cfloat.f64_sub(a1._c_float, a2._c_float)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_mul(Float64 a1, Float64 a2):
+    cdef cfloat.float64_t f = cfloat.f64_mul(a1._c_float, a2._c_float)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_fma(Float64 a1, Float64 a2, Float64 a3):
+    cdef cfloat.float64_t f = cfloat.f64_mulAdd(a1._c_float, a2._c_float, a3._c_float)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_qma(Float64 a3, Float64 a1, Float64 a2):
+    cdef cfloat.float64_t f = cfloat.f64_mulAdd(a1._c_float, a2._c_float, a3._c_float)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_div(Float64 a1, Float64 a2):
+    cdef cfloat.float64_t f = cfloat.f64_div(a1._c_float, a2._c_float)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_rem(Float64 a1, Float64 a2):
+    cdef cfloat.float64_t f = cfloat.f64_rem(a1._c_float, a2._c_float)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_sqrt(Float64 a1):
+    cdef cfloat.float64_t f = cfloat.f64_sqrt(a1._c_float)
+    return Float64.from_c_float(f)
+
+cpdef bint f64_eq(Float64 a1, Float64 a2):
+    return cfloat.f64_eq(a1._c_float, a2._c_float)
+
+cpdef bint f64_le(Float64 a1, Float64 a2):
+    return cfloat.f64_le(a1._c_float, a2._c_float)
+
+cpdef bint f64_lt(Float64 a1, Float64 a2):
+    return cfloat.f64_lt(a1._c_float, a2._c_float)
+
+cpdef Float16 f64_to_f16(Float64 a1):
+    cdef cfloat.float16_t f = cfloat.f64_to_f16(a1._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float32 f64_to_f32(Float64 a1):
+    cdef cfloat.float32_t f = cfloat.f64_to_f32(a1._c_float)
+    return Float32.from_c_float(f)