aboutsummaryrefslogtreecommitdiffstats
path: root/examples/using_double_on_avr/double_conversion.c
diff options
context:
space:
mode:
authorPetteri Aimonen <jpa@git.mail.kapsi.fi>2013-09-13 12:59:31 +0300
committerPetteri Aimonen <jpa@git.mail.kapsi.fi>2013-09-13 12:59:31 +0300
commitf47410ea4b8ae43e19facd378be4cf1073e1813b (patch)
tree53fdc4bac6615f07e830d7d538c90abbea1ead4b /examples/using_double_on_avr/double_conversion.c
parentfd9a79a06db00c6199a5dcaee22ed2cd8e3c3e9b (diff)
Move examples into subfolders, add READMEs
Diffstat (limited to 'examples/using_double_on_avr/double_conversion.c')
-rw-r--r--examples/using_double_on_avr/double_conversion.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/examples/using_double_on_avr/double_conversion.c b/examples/using_double_on_avr/double_conversion.c
new file mode 100644
index 00000000..cf79b9a0
--- /dev/null
+++ b/examples/using_double_on_avr/double_conversion.c
@@ -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;
+}
+
+