mirror of
https://github.com/ksherlock/mpw.git
synced 2024-11-21 09:30:55 +00:00
code for decomposing float/double/long double, proper FX2DEC NaN support.
This commit is contained in:
parent
563dd0f485
commit
559f36c437
@ -28,6 +28,7 @@ set(TOOLBOX_SRC
|
||||
fs_spec.cpp
|
||||
realpath.c
|
||||
dispatch.cpp
|
||||
fpinfo.cpp
|
||||
)
|
||||
|
||||
|
||||
|
106
toolbox/fpinfo.cpp
Normal file
106
toolbox/fpinfo.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include "fpinfo.h"
|
||||
|
||||
#include <machine/endian.h>
|
||||
|
||||
|
||||
static_assert(sizeof(float) == 4, "Unexpected float size");
|
||||
static_assert(sizeof(double) == 8, "Unexpected double size");
|
||||
static_assert(sizeof(long double) == 8 || sizeof(long double) == 16, "Unexpected long double size");
|
||||
|
||||
void fpinfo::init(float *f)
|
||||
{
|
||||
union split {
|
||||
float f;
|
||||
uint32_t i;
|
||||
};
|
||||
|
||||
uint32_t i = ((split *)f)->i;
|
||||
|
||||
sign = i >> 31;
|
||||
one = 1;
|
||||
exp = (i >> 23) & ((1 << 8) - 1);
|
||||
sig = i & ((1 << 24) - 1);
|
||||
|
||||
if (exp == 255) {
|
||||
if (sig == 0) inf = true;
|
||||
else nan = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (exp == 0) {
|
||||
// 0 or denormalized.
|
||||
one = 0;
|
||||
exp = -126;
|
||||
return;
|
||||
}
|
||||
|
||||
exp -= 127; // bias
|
||||
}
|
||||
|
||||
void fpinfo::init(double *d)
|
||||
{
|
||||
|
||||
union split {
|
||||
double d;
|
||||
uint64_t i;
|
||||
};
|
||||
|
||||
uint64_t i = ((split *)d)->i;
|
||||
|
||||
sign = i >> 63;
|
||||
one = 1;
|
||||
exp = (i >> 52) & ((1 << 11) - 1);
|
||||
sig = i & ((UINT64_C(1) << 53) - 1);
|
||||
|
||||
|
||||
if (exp == 2047) {
|
||||
if (sig == 0) inf = true;
|
||||
else nan = true;
|
||||
return;
|
||||
}
|
||||
if (exp == 0) {
|
||||
// 0 or denormalized.
|
||||
one = 0;
|
||||
exp = -1022;
|
||||
return;
|
||||
}
|
||||
|
||||
exp -= 1023; // bias
|
||||
}
|
||||
|
||||
void fpinfo::init(long double *ld)
|
||||
{
|
||||
|
||||
union split {
|
||||
long double ld;
|
||||
uint64_t i[2];
|
||||
};
|
||||
|
||||
uint64_t i;
|
||||
uint32_t sexp;
|
||||
|
||||
|
||||
// this needs to be verified.
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
i = ((split *)ld)->i[0];
|
||||
sexp = ((split *)ld)->i[1];
|
||||
#else
|
||||
i = ((split *)ld)->i[1];
|
||||
sexp = ((split *)ld)->i[0];
|
||||
#endif
|
||||
|
||||
sign = sexp >> 15;
|
||||
sig = sexp & ((1 << 15) - 1);
|
||||
|
||||
one = i >> 63;
|
||||
sig = i & ((UINT64_C(1) << 63) - 1);
|
||||
|
||||
if (exp == 32767) {
|
||||
if (sig == 0) inf = true;
|
||||
else nan = true;
|
||||
return;
|
||||
}
|
||||
//
|
||||
|
||||
exp -= 16383;
|
||||
}
|
29
toolbox/fpinfo.h
Normal file
29
toolbox/fpinfo.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef __fpinfo_h__
|
||||
#define __fpinfo_h__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct fpinfo {
|
||||
bool sign = false;
|
||||
bool one = false;
|
||||
int exp = 0;
|
||||
uint64_t sig = 0;
|
||||
|
||||
bool nan = false;
|
||||
bool inf = false;
|
||||
|
||||
fpinfo(float f) { init(&f); }
|
||||
fpinfo(double d) { init(&d); }
|
||||
fpinfo(long double ld) {
|
||||
if (sizeof(long double) == 16) init(&ld);
|
||||
if (sizeof(long double) == 8) init((double *)&ld);
|
||||
}
|
||||
|
||||
private:
|
||||
void init(float *);
|
||||
void init(double *);
|
||||
void init(long double *);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include "stackframe.h"
|
||||
#include "complex.h"
|
||||
#include "fpinfo.h"
|
||||
|
||||
using ToolBox::Log;
|
||||
|
||||
@ -104,6 +105,8 @@ using its_complicated::signbit;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// long double is an 80-bit extended with an extra 48-bits of 0 padding.
|
||||
@ -354,6 +357,9 @@ using its_complicated::signbit;
|
||||
|
||||
if (df.digits < 0) df.digits = 0;
|
||||
|
||||
fpinfo fpi(s);
|
||||
//fprintf(stderr, "%02x %02x %08x %016llx\n", fpi.sign, fpi.one, fpi.exp, fpi.sig);
|
||||
|
||||
// handle infinity, nan as a special case.
|
||||
switch (fpclassify(s))
|
||||
{
|
||||
@ -364,11 +370,14 @@ using its_complicated::signbit;
|
||||
return 0;
|
||||
|
||||
case FP_NAN:
|
||||
// NAN type should be encoded in the sig.
|
||||
// 3.2 CSANELib.o nan() function is broken.
|
||||
d.sgn = signbit(s);
|
||||
d.sig = "N40xx000000000000";
|
||||
d.write(d_adr);
|
||||
// NAN type encoded in the sig.
|
||||
{
|
||||
char buffer[20]; // 16 + 2 needed
|
||||
snprintf(buffer, 20, "N%016llx", fpi.sig);
|
||||
d.sgn = signbit(s);
|
||||
d.sig = buffer;
|
||||
d.write(d_adr);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case FP_INFINITE:
|
||||
@ -383,6 +392,7 @@ using its_complicated::signbit;
|
||||
|
||||
}
|
||||
|
||||
// normal and subnormal handled here....
|
||||
|
||||
#if 0
|
||||
if (df.style == decform::FIXEDDECIMAL)
|
||||
|
Loading…
Reference in New Issue
Block a user