浏览代码

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

fslongjin 2 年之前
父节点
当前提交
7670031b11

+ 2 - 1
.vscode/settings.json

@@ -103,7 +103,8 @@
         "stddef.h": "c",
         "spinlock.h": "c",
         "stat.h": "c",
-        "video.h": "c"
+        "video.h": "c",
+        "libm.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 1 - 1
kernel/common/Makefile

@@ -1,7 +1,7 @@
 
 CFLAGS += -I .
 
-kernel_common_subdirs:=libELF
+kernel_common_subdirs:=libELF math
 
 all: glib.o
 	@list='$(kernel_common_subdirs)'; for subdir in $$list; do \

+ 3 - 0
kernel/common/math.h

@@ -0,0 +1,3 @@
+#pragma once
+#include "stddef.h"
+int64_t pow(int64_t x, int y);

+ 14 - 0
kernel/common/math/Makefile

@@ -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 - 0
kernel/common/math/fabs.c

@@ -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 - 0
kernel/common/math/libm.h

@@ -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 - 0
kernel/common/math/pow.c

@@ -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;
+}

+ 43 - 0
kernel/common/math/round.c

@@ -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;
+}

+ 17 - 11
kernel/common/printk.c

@@ -9,7 +9,7 @@
 
 #include <driver/uart/uart.h>
 #include <driver/video/video.h>
-
+#include "math.h"
 //#include "linkage.h"
 
 struct printk_screen_info pos;
@@ -535,6 +535,7 @@ static char *write_num(char *str, ul num, int base, int field_width, int precisi
     return str;
 }
 
+
 static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags)
 {
     /**
@@ -572,11 +573,11 @@ static char *write_float_point_num(char *str, double num, int field_width, int p
     if (sign)
         --field_width;
 
-    int js_num_z = 0, js_num_d = 0;                          // 临时数字字符串tmp_num_z tmp_num_d的长度
-    ul num_z = (ul)(num);                                    // 获取整数部分
-    ul num_decimal = (ul)(round((num - num_z) * precision)); // 获取小数部分
+    int js_num_z = 0, js_num_d = 0;                                               // 临时数字字符串tmp_num_z tmp_num_d的长度
+    uint64_t num_z = (uint64_t)(num);                                             // 获取整数部分
+    uint64_t num_decimal = (uint64_t)(round(1.0*(num - num_z) * pow(10, precision))); // 获取小数部分
 
-    if (num == 0)
+    if (num == 0 || num_z == 0)
         tmp_num_z[js_num_z++] = '0';
     else
     {
@@ -605,18 +606,23 @@ static char *write_float_point_num(char *str, double num, int field_width, int p
         *str++ = sign;
 
     // 输出整数部分
-    while (js_num_z-- > 0)
-        *str++ = tmp_num_z[js_num_z];
-
+    // while (js_num_z-- > 0)
+    //     *str++ = tmp_num_z[js_num_z];
+    while (js_num_z > 0)
+    {
+        *str++ = tmp_num_z[js_num_z - 1];
+        --js_num_z;
+    }
     *str++ = '.';
 
     // 输出小数部分
-    while (js_num_d-- > 0)
+    int total_dec_count = js_num_d;
+    for (int i = 0; i < precision && js_num_d-- > 0; ++i)
         *str++ = tmp_num_d[js_num_d];
 
-    while (js_num_d < precision)
+    while (total_dec_count < precision)
     {
-        --precision;
+        ++total_dec_count;
         *str++ = '0';
     }
 

+ 1 - 1
run.sh

@@ -107,7 +107,7 @@ if [ $flag_can_run -eq 1 ]; then
     else
         qemu-system-x86_64 -cdrom ${iso} -m 512M -smp 2,cores=2,threads=1,sockets=1 \
         -boot order=d   \
-        -monitor stdio -d cpu_reset,guest_errors,trace:check_exception,exec,cpu,out_asm,in_asm -s -S -cpu "IvyBridge,+apic,+x2apic,check,${allflags}" --enable-kvm -rtc clock=host,base=localtime -serial file:serial_opt.txt \
+        -monitor stdio -d cpu_reset,guest_errors,trace:check_exception,exec,cpu,out_asm,in_asm -s -S -cpu "IvyBridge,+apic,+x2apic,+fpu,check,${allflags}" --enable-kvm -rtc clock=host,base=localtime -serial file:serial_opt.txt \
         -drive id=disk,file=bin/disk.img,if=none \
         -device ahci,id=ahci \
         -device ide-hd,drive=disk,bus=ahci.0    \

+ 4 - 2
user/apps/about/about.c

@@ -1,6 +1,8 @@
 #include <libc/stdio.h>
 #include <libc/stdlib.h>
 #include <libc/unistd.h>
+#include <libc/time.h>
+#include <libc/math.h>
 
 void print_ascii_logo()
 {
@@ -26,11 +28,11 @@ int main()
 {
     // printf("Hello World!\n");
     print_ascii_logo();
-    usleep(500000);
-    usleep(500000);
+    
     print_copyright();
     // exit(0);
     // while (1)
     //     ;
+
     return 0;
 }

+ 4 - 2
user/libs/libc/math.h

@@ -1,5 +1,5 @@
 #pragma once
-
+#include "stddef.h"
 
 double fabs(double x);
 float fabsf(float x);
@@ -7,4 +7,6 @@ long double fabsl(long double x);
 
 double round(double x);
 float roundf(float x);
-long double roundl(long double x);
+long double roundl(long double x);
+
+int64_t pow(int64_t x, int y);

+ 5 - 2
user/libs/libc/math/Makefile

@@ -1,11 +1,14 @@
 
-all: fabs.o round.o
 
 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
+	gcc $(CFLAGS) -c round.c -o round.o
+
+pow.o: pow.c
+	gcc $(CFLAGS) -c pow.c -o pow.o

+ 1 - 0
user/libs/libc/math/fabs.c

@@ -1,6 +1,7 @@
 #include <libc/math.h>
 #include <libc/sys/types.h>
 #include "libm.h"
+
 double fabs(double x)
 {
     union

+ 10 - 0
user/libs/libc/math/pow.c

@@ -0,0 +1,10 @@
+#include "math.h"
+#include <libc/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;
+}

+ 15 - 15
user/libs/libc/printf.c

@@ -9,7 +9,6 @@
 static char *write_num(char *str, uint64_t num, int base, int field_width, int precision, int flags);
 static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags);
 
-
 static int skip_and_atoi(const char **s)
 {
     /**
@@ -323,10 +322,6 @@ int vsprintf(char *buf, const char *fmt, va_list args)
             break;
         case 'f':
             // 默认精度为3
-            // printk("1111\n");
-            // va_arg(args, double);
-            // printk("222\n");
-
             if (precision < 0)
                 precision = 3;
 
@@ -497,11 +492,11 @@ static char *write_float_point_num(char *str, double num, int field_width, int p
     if (sign)
         --field_width;
 
-    int js_num_z = 0, js_num_d = 0;                                      // 临时数字字符串tmp_num_z tmp_num_d的长度
-    uint64_t num_z = (uint64_t)(num);                                    // 获取整数部分
-    uint64_t num_decimal = (uint64_t)(round((num - num_z) * precision)); // 获取小数部分
+    int js_num_z = 0, js_num_d = 0;                                               // 临时数字字符串tmp_num_z tmp_num_d的长度
+    uint64_t num_z = (uint64_t)(num);                                             // 获取整数部分
+    uint64_t num_decimal = (uint64_t)(round(1.0*(num - num_z) * pow(10, precision))); // 获取小数部分
 
-    if (num == 0)
+    if (num == 0 || num_z == 0)
         tmp_num_z[js_num_z++] = '0';
     else
     {
@@ -530,18 +525,23 @@ static char *write_float_point_num(char *str, double num, int field_width, int p
         *str++ = sign;
 
     // 输出整数部分
-    while (js_num_z-- > 0)
-        *str++ = tmp_num_z[js_num_z];
-
+    // while (js_num_z-- > 0)
+    //     *str++ = tmp_num_z[js_num_z];
+    while (js_num_z > 0)
+    {
+        *str++ = tmp_num_z[js_num_z - 1];
+        --js_num_z;
+    }
     *str++ = '.';
 
     // 输出小数部分
-    while (js_num_d-- > 0)
+    int total_dec_count = js_num_d;
+    for (int i = 0; i < precision && js_num_d-- > 0; ++i)
         *str++ = tmp_num_d[js_num_d];
 
-    while (js_num_d < precision)
+    while (total_dec_count < precision)
     {
-        --precision;
+        ++total_dec_count;
         *str++ = '0';
     }