bugfix: 修复浮点数打印错误的bug

This commit is contained in:
fslongjin
2022-07-12 13:19:51 +08:00
parent 676260c537
commit 7670031b11
16 changed files with 235 additions and 35 deletions

View File

@ -0,0 +1,14 @@
CFLAGS += -I .
all: fabs.o round.o pow.o
fabs.o: fabs.c
gcc $(CFLAGS) -c fabs.c -o fabs.o
round.o: round.c
gcc $(CFLAGS) -c round.c -o round.o
pow.o: pow.c
gcc $(CFLAGS) -c pow.c -o pow.o

30
kernel/common/math/fabs.c Normal file
View File

@ -0,0 +1,30 @@
#include <common/math.h>
#include <common/sys/types.h>
#include "libm.h"
double fabs(double x)
{
union
{
double f;
uint64_t i;
} u = {x};
u.i &= -1ULL / 2;
return u.f;
}
#if __LDBL_MANT_DIG__ == 53 && __LDBL_MAX_EXP__ == 1024
long double fabsl(long double x)
{
return fabs(x);
}
#elif (__LDBL_MANT_DIG__ == 64 || __LDBL_MANT_DIG__ == 113) && __LDBL_MAX_EXP__ == 16384
long double fabsl(long double x)
{
union ldshape u = {x};
u.i.se &= 0x7fff;
return u.f;
}
#endif

75
kernel/common/math/libm.h Normal file
View File

@ -0,0 +1,75 @@
#pragma once
#include <common/sys/types.h>
// ===== 描述long double 的数据比特结构
#if __LDBL_MANT_DIG__ == 53 && __LDBL_MAX_EXP__ == 1024
#elif __LDBL_MANT_DIG__ == 64 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
union ldshape
{
long double f;
struct
{
uint64_t m;
uint16_t se;
} i;
};
#elif __LDBL_MANT_DIG__ == 113 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
union ldshape
{
long double f;
struct
{
uint64_t lo;
uint32_t mid;
uint16_t top;
uint16_t se;
} i;
struct
{
uint64_t lo;
uint64_t hi;
} i2;
};
#elif __LDBL_MANT_DIG__ == 113 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __BIG_ENDIAN
union ldshape
{
long double f;
struct
{
uint16_t se;
uint16_t top;
uint32_t mid;
uint64_t lo;
} i;
struct
{
uint64_t hi;
uint64_t lo;
} i2;
};
#else
#error Unsupported long double representation
#endif
#define FORCE_EVAL(x) \
do \
{ \
if (sizeof(x) == sizeof(float)) \
{ \
volatile float __x; \
__x = (x); \
(void)__x; \
} \
else if (sizeof(x) == sizeof(double)) \
{ \
volatile double __x; \
__x = (x); \
(void)__x; \
} \
else \
{ \
volatile long double __x; \
__x = (x); \
(void)__x; \
} \
} while (0)

10
kernel/common/math/pow.c Normal file
View File

@ -0,0 +1,10 @@
#include <common/math.h>
#include <common/stddef.h>
int64_t pow(int64_t x, int y)
{
int64_t res = 1;
for (int i = 0; i < y; ++i)
res *= x;
return res;
}

View File

@ -0,0 +1,43 @@
#include "libm.h"
#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1
#define EPS __DBL_EPSILON__
#elif __FLT_EVAL_METHOD__ == 2
#define EPS __LDBL_EPSILON__
#endif
static const double toint = 1 / EPS;
double round(double x)
{
union
{
double f;
uint64_t i;
} u = {x};
int e = u.i >> 52 & 0x7ff;
double y;
if (e >= 0x3ff + 52)
return x;
if (u.i >> 63)
x = -x;
if (e < 0x3ff - 1)
{
/* raise inexact if x!=0 */
FORCE_EVAL(x + toint);
return 0 * u.f;
}
y = x + toint - toint - x;
if (y > 0.5)
y = y + x - 1;
else if (y <= -0.5)
y = y + x + 1;
else
y = y + x;
if (u.i >> 63)
y = -y;
return y;
}