mirror of
https://github.com/ksherlock/mpw.git
synced 2024-11-24 13:32:39 +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
|
fs_spec.cpp
|
||||||
realpath.c
|
realpath.c
|
||||||
dispatch.cpp
|
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 "stackframe.h"
|
||||||
#include "complex.h"
|
#include "complex.h"
|
||||||
|
#include "fpinfo.h"
|
||||||
|
|
||||||
using ToolBox::Log;
|
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.
|
// 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;
|
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.
|
// handle infinity, nan as a special case.
|
||||||
switch (fpclassify(s))
|
switch (fpclassify(s))
|
||||||
{
|
{
|
||||||
@ -364,11 +370,14 @@ using its_complicated::signbit;
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case FP_NAN:
|
case FP_NAN:
|
||||||
// NAN type should be encoded in the sig.
|
// NAN type encoded in the sig.
|
||||||
// 3.2 CSANELib.o nan() function is broken.
|
{
|
||||||
d.sgn = signbit(s);
|
char buffer[20]; // 16 + 2 needed
|
||||||
d.sig = "N40xx000000000000";
|
snprintf(buffer, 20, "N%016llx", fpi.sig);
|
||||||
d.write(d_adr);
|
d.sgn = signbit(s);
|
||||||
|
d.sig = buffer;
|
||||||
|
d.write(d_adr);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case FP_INFINITE:
|
case FP_INFINITE:
|
||||||
@ -383,6 +392,7 @@ using its_complicated::signbit;
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// normal and subnormal handled here....
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (df.style == decform::FIXEDDECIMAL)
|
if (df.style == decform::FIXEDDECIMAL)
|
||||||
|
Loading…
Reference in New Issue
Block a user