blob: cf79b9a00da6f1d27546fc73c25ab6b43e6bbbe0 [file] [log] [blame]
/* 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;
}