Separation Generator to a dedicated repo
[apps/agl-service-can-low-level.git] / libs / nanopb / examples / using_double_on_avr / double_conversion.c
diff --git a/libs/nanopb/examples/using_double_on_avr/double_conversion.c b/libs/nanopb/examples/using_double_on_avr/double_conversion.c
new file mode 100644 (file)
index 0000000..cf79b9a
--- /dev/null
@@ -0,0 +1,123 @@
+/* Conversion routines for platforms that do not support 'double' directly. */
+
+#include "double_conversion.h"
+#include <math.h>
+
+typedef union {
+    float f;
+    uint32_t i;
+} conversion_t;
+
+/* Note: IEE 754 standard specifies float formats as follows:
+ * Single precision: sign,  8-bit exp, 23-bit frac.
+ * Double precision: sign, 11-bit exp, 52-bit frac.
+ */
+
+uint64_t float_to_double(float value)
+{
+    conversion_t in;
+    in.f = value;
+    uint8_t sign;
+    int16_t exponent;
+    uint64_t mantissa;
+    
+    /* Decompose input value */
+    sign = (in.i >> 31) & 1;
+    exponent = ((in.i >> 23) & 0xFF) - 127;
+    mantissa = in.i & 0x7FFFFF;
+    
+    if (exponent == 128)
+    {
+        /* Special value (NaN etc.) */
+        exponent = 1024;
+    }
+    else if (exponent == -127)
+    {
+        if (!mantissa)
+        {
+            /* Zero */
+            exponent = -1023;
+        }
+        else
+        {
+            /* Denormalized */
+            mantissa <<= 1;
+            while (!(mantissa & 0x800000))
+            {
+                mantissa <<= 1;
+                exponent--;
+            }
+            mantissa &= 0x7FFFFF;
+        }
+    }
+    
+    /* Combine fields */
+    mantissa <<= 29;
+    mantissa |= (uint64_t)(exponent + 1023) << 52;
+    mantissa |= (uint64_t)sign << 63;
+    
+    return mantissa;
+}
+
+float double_to_float(uint64_t value)
+{
+    uint8_t sign;
+    int16_t exponent;
+    uint32_t mantissa;
+    conversion_t out;
+
+    /* Decompose input value */
+    sign = (value >> 63) & 1;
+    exponent = ((value >> 52) & 0x7FF) - 1023;
+    mantissa = (value >> 28) & 0xFFFFFF; /* Highest 24 bits */
+    /* Figure if value is in range representable by floats. */
+    if (exponent == 1024)
+    {
+        /* Special value */
+        exponent = 128;
+    }
+    else if (exponent > 127)
+    {
+        /* Too large */        
+        if (sign)
+            return -INFINITY;
+        else
+            return INFINITY;
+    }
+    else if (exponent < -150)
+    {
+        /* Too small */
+        if (sign)
+            return -0.0f;
+        else
+            return 0.0f;
+    }
+    else if (exponent < -126)
+    {
+        /* Denormalized */
+        mantissa |= 0x1000000;
+        mantissa >>= (-126 - exponent);
+        exponent = -127;
+    }
+    /* Round off mantissa */
+    mantissa = (mantissa + 1) >> 1;
+    
+    /* Check if mantissa went over 2.0 */
+    if (mantissa & 0x800000)
+    {
+        exponent += 1;
+        mantissa &= 0x7FFFFF;
+        mantissa >>= 1;
+    }
+    
+    /* Combine fields */
+    out.i = mantissa;
+    out.i |= (uint32_t)(exponent + 127) << 23;
+    out.i |= (uint32_t)sign << 31;
+    
+    return out.f;
+}
+
+