add negation and absolute value
[sfpy.git] / sfpy / float.pyx
index d25a6dacc254a7f7446d256882f725e2dfa0dead..968323f8f0f90191ad09702f69b68913b069bfb7 100644 (file)
@@ -110,6 +110,33 @@ cpdef void flag_clear_invalid():
     cfloat.softfloat_exceptionFlags &= ~cfloat.softfloat_flag_invalid
 
 
+# C helpers
+
+cdef inline cfloat.float16_t _f16_neg(cfloat.float16_t f):
+    f.v ^= 0x8000
+    return f
+
+cdef inline cfloat.float32_t _f32_neg(cfloat.float32_t f):
+    f.v ^= 0x80000000
+    return f
+
+cdef inline cfloat.float64_t _f64_neg(cfloat.float64_t f):
+    f.v ^= 0x8000000000000000
+    return f
+
+cdef inline cfloat.float16_t _f16_abs(cfloat.float16_t f):
+    f.v &= 0x7fff
+    return f
+
+cdef inline cfloat.float32_t _f32_abs(cfloat.float32_t f):
+    f.v &= 0x7fffffff
+    return f
+
+cdef inline cfloat.float64_t _f64_abs(cfloat.float64_t f):
+    f.v &= 0x7fffffffffffffff
+    return f
+
+
 cdef class Float16:
 
     # the wrapped float value
@@ -188,6 +215,20 @@ cdef class Float16:
 
     # arithmetic
 
+    cpdef Float16 neg(self):
+        cdef cfloat.float16_t f = _f16_neg(self._c_float)
+        return Float16.from_c_float(f)
+
+    def __neg__(self):
+        return self.neg()
+
+    cpdef Float16 abs(self):
+        cdef cfloat.float16_t f = _f16_abs(self._c_float)
+        return Float16.from_c_float(f)
+
+    def __abs__(self):
+        return self.abs()
+
     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)
@@ -245,6 +286,12 @@ cdef class Float16:
 
     # in-place arithmetic
 
+    cpdef void ineg(self):
+        self._c_float = _f16_neg(self._c_float)
+
+    cpdef void iabs(self):
+        self._c_float = _f16_abs(self._c_float)
+
     cpdef void iround_to(self, uint_fast8_t rm, bint exact):
         self._c_float = cfloat.f16_roundToInt(self._c_float, rm, exact)
 
@@ -333,6 +380,14 @@ cdef class Float16:
 
 # external, non-method arithmetic
 
+cpdef Float16 f16_neg(Float16 a1):
+    cdef cfloat.float16_t f = _f16_neg(a1._c_float)
+    return Float16.from_c_float(f)
+
+cpdef Float16 f16_abs(Float16 a1):
+    cdef cfloat.float16_t f = _f16_abs(a1._c_float)
+    return Float16.from_c_float(f)
+
 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)
@@ -469,6 +524,20 @@ cdef class Float32:
 
     # arithmetic
 
+    cpdef Float32 neg(self):
+        cdef cfloat.float32_t f = _f32_neg(self._c_float)
+        return Float32.from_c_float(f)
+
+    def __neg__(self):
+        return self.neg()
+
+    cpdef Float32 abs(self):
+        cdef cfloat.float32_t f = _f32_abs(self._c_float)
+        return Float32.from_c_float(f)
+
+    def __abs__(self):
+        return self.abs()
+
     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)
@@ -526,6 +595,12 @@ cdef class Float32:
 
     # in-place arithmetic
 
+    cpdef void ineg(self):
+        self._c_float = _f32_neg(self._c_float)
+
+    cpdef void iabs(self):
+        self._c_float = _f32_abs(self._c_float)
+
     cpdef void iround_to(self, uint_fast8_t rm, bint exact):
         self._c_float = cfloat.f32_roundToInt(self._c_float, rm, exact)
 
@@ -614,6 +689,14 @@ cdef class Float32:
 
 # external, non-method arithmetic
 
+cpdef Float32 f32_neg(Float32 a1):
+    cdef cfloat.float32_t f = _f32_neg(a1._c_float)
+    return Float32.from_c_float(f)
+
+cpdef Float32 f32_abs(Float32 a1):
+    cdef cfloat.float32_t f = _f32_abs(a1._c_float)
+    return Float32.from_c_float(f)
+
 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)
@@ -748,6 +831,20 @@ cdef class Float64:
 
     # arithmetic
 
+    cpdef Float64 neg(self):
+        cdef cfloat.float64_t f = _f64_neg(self._c_float)
+        return Float64.from_c_float(f)
+
+    def __neg__(self):
+        return self.neg()
+
+    cpdef Float64 abs(self):
+        cdef cfloat.float64_t f = _f64_abs(self._c_float)
+        return Float64.from_c_float(f)
+
+    def __abs__(self):
+        return self.abs()
+
     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)
@@ -805,6 +902,12 @@ cdef class Float64:
 
     # in-place arithmetic
 
+    cpdef void ineg(self):
+        self._c_float = _f64_neg(self._c_float)
+
+    cpdef void iabs(self):
+        self._c_float = _f64_abs(self._c_float)
+
     cpdef void iround_to(self, uint_fast8_t rm, bint exact):
         self._c_float = cfloat.f64_roundToInt(self._c_float, rm, exact)
 
@@ -893,6 +996,14 @@ cdef class Float64:
 
 # external, non-method arithmetic
 
+cpdef Float64 f64_neg(Float64 a1):
+    cdef cfloat.float64_t f = _f64_neg(a1._c_float)
+    return Float64.from_c_float(f)
+
+cpdef Float64 f64_abs(Float64 a1):
+    cdef cfloat.float64_t f = _f64_abs(a1._c_float)
+    return Float64.from_c_float(f)
+
 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)