17ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Conversion routines for platforms that do not support 'double' directly. */
27ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
37ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "double_conversion.h"
47ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <math.h>
57ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
67ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohentypedef union {
77ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    float f;
87ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint32_t i;
97ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} conversion_t;
107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Note: IEE 754 standard specifies float formats as follows:
127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Single precision: sign,  8-bit exp, 23-bit frac.
137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Double precision: sign, 11-bit exp, 52-bit frac.
147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */
157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenuint64_t float_to_double(float value)
177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    conversion_t in;
197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    in.f = value;
207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint8_t sign;
217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    int16_t exponent;
227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint64_t mantissa;
237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Decompose input value */
257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    sign = (in.i >> 31) & 1;
267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    exponent = ((in.i >> 23) & 0xFF) - 127;
277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    mantissa = in.i & 0x7FFFFF;
287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (exponent == 128)
307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Special value (NaN etc.) */
327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        exponent = 1024;
337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else if (exponent == -127)
357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!mantissa)
377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            /* Zero */
397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            exponent = -1023;
407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        else
427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            /* Denormalized */
447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            mantissa <<= 1;
457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            while (!(mantissa & 0x800000))
467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            {
477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                mantissa <<= 1;
487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                exponent--;
497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            }
507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            mantissa &= 0x7FFFFF;
517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Combine fields */
557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    mantissa <<= 29;
567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    mantissa |= (uint64_t)(exponent + 1023) << 52;
577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    mantissa |= (uint64_t)sign << 63;
587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return mantissa;
607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenfloat double_to_float(uint64_t value)
637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint8_t sign;
657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    int16_t exponent;
667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint32_t mantissa;
677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    conversion_t out;
687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Decompose input value */
707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    sign = (value >> 63) & 1;
717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    exponent = ((value >> 52) & 0x7FF) - 1023;
727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    mantissa = (value >> 28) & 0xFFFFFF; /* Highest 24 bits */
737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Figure if value is in range representable by floats. */
757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (exponent == 1024)
767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Special value */
787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        exponent = 128;
797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else if (exponent > 127)
817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Too large */
837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (sign)
847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return -INFINITY;
857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        else
867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return INFINITY;
877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else if (exponent < -150)
897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Too small */
917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (sign)
927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return -0.0f;
937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        else
947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return 0.0f;
957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else if (exponent < -126)
977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Denormalized */
997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        mantissa |= 0x1000000;
1007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        mantissa >>= (-126 - exponent);
1017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        exponent = -127;
1027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Round off mantissa */
1057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    mantissa = (mantissa + 1) >> 1;
1067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Check if mantissa went over 2.0 */
1087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (mantissa & 0x800000)
1097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
1107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        exponent += 1;
1117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        mantissa &= 0x7FFFFF;
1127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        mantissa >>= 1;
1137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Combine fields */
1167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    out.i = mantissa;
1177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    out.i |= (uint32_t)(exponent + 127) << 23;
1187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    out.i |= (uint32_t)sign << 31;
1197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return out.f;
1217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
1227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
124