登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
轻量养虾,开箱即用!低 Token + 稳定算力,Gitee & 模力方舟联合出品的 PocketClaw 正式开售!点击了解详情~
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
16
Star
101
Fork
54
aosp-riscv
/
working-group
代码
Issues
15
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
开发画像分析
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
math 库浮点圆整问题
已完成
#I5BV63
unicornx
拥有者
创建于
2022-06-12 13:57
# 1. 整体分析 ``` [ FAILED ] math_h.lrint [ FAILED ] math_h.rint [ FAILED ] math_h.nearbyint [ FAILED ] math_h_force_long_double.lrint [ FAILED ] math_h_force_long_double.rint [ FAILED ] math_h_force_long_double.nearbyint ``` - lrint:执行单元测试 math_h.lrint 失败,期望返回 1235,但实际返回 1234,和 `rintl()` 函数有关, ```cpp ASSERT_EQ(1235, lrintl(1234.01L)); ``` - rint:失败在 `ASSERT_EQ(1235.0, rintl(1234.01L));` 所以原因和 lrint 的测试应该相同,也是和 `rintl()` 函数有关。 - nearbyint:失败在 `ASSERT_EQ(1235.0, nearbyintl(1234.01L));` 参考 `bionic/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c` ```cpp DECL(long double, nearbyintl, rintl) ``` 所以同样和 rintl 函数有关。 math_h_force_long_double 同 math_h,参考 `bionic/tests/math_force_long_double_test.cpp` ```cpp #define __BIONIC_LP32_USE_LONG_DOUBLE #include "math_test.cpp" ``` # 2. lrintl 函数分析 ## 2.1 32 位平台 参考 `bionic/libm/fake_long_double.c` ```cpp #if !defined(__LP64__) ...... #if !defined(__i386__) // x86 has an assembler lrint/lrintl. long lrintl(long double a1) { return lrint(a1); } #endif ... #endif // __LP64__ ``` 在 32 位平台下,x86 提供了汇编代码实现的 lrint/lrintl,其他的平台则采用 lrint 代替。但我们目前调试的是 riscv64 所以暂时不管 32 位平台的问题。 ## 2.2 64 位平台 实现参考 `bionic/libm/upstream-freebsd/lib/msun/src/s_lrintl.c` ```cpp #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); #define type long double #define roundit rintl #define dtype long #define fn lrintl #include "s_lrint.c" ``` 代入宏后展开最终内部实现指向的是 `rintl()`, 实现在 `bionic/libm/upstream-freebsd/lib/msun/src/s_rintl.c` 所以 lrintl 函数最终实际调用 `rintl()`, 抽取代码后源码见 <https://compiler-explorer.com/z/59TcePcvE>, 类似代码在 gcc 环境下测试 pass。 调试后发现 clang 编译环境下, 执行 `x += shift[sign];` 这句出现问题。 反汇编后如下: ```cpp 0x000000000047d06e <rintl+76>: 93 1a 25 00 slli s5,a0,0x2 0x000000000047d072 <rintl+80>: 17 25 bd ff auipc a0,0xffbd2 0x000000000047d076 <rintl+84>: 13 05 65 99 addi a0,a0,-1642 # 0x4ea08 <shift> 0x000000000047d07a <rintl+88>: 56 95 add a0,a0,s5 0x000000000047d07c <rintl+90>: 07 25 05 00 flw fa0,0(a0) 0x000000000047d080 <rintl+94>: 97 00 07 00 auipc ra,0x70 0x000000000047d084 <rintl+98>: e7 80 e0 76 jalr 1902(ra) # 0x4ed7ee <__extendsftf2> 0x000000000047d088 <rintl+102>: 2a 89 mv s2,a0 0x000000000047d08a <rintl+104>: ae 89 mv s3,a1 0x000000000047d08c <rintl+106>: 5e 86 mv a2,s7 0x000000000047d08e <rintl+108>: a2 86 mv a3,s0 0x000000000047d090 <rintl+110>: 97 f0 06 00 auipc ra,0x6f 0x000000000047d094 <rintl+114>: e7 80 e0 6a jalr 1710(ra) # 0x4ec73e <__addtf3> ``` 单步调试发现执行 0x000000000047d094 即调用 __addtf3 时返回的结果和 gcc 下的不同, 导致最后结果出错。 gcc 返回的 a0 = 0x00000000000004d3,a1 = 0x406f000000000000 clang 返回的 a0 = 0x00000000000004d2,a1 = 0x406f000000000000 所以我初步猜测,汇编的结果没有问题,出错是在调用 __addtf3 的实现有问题。
# 1. 整体分析 ``` [ FAILED ] math_h.lrint [ FAILED ] math_h.rint [ FAILED ] math_h.nearbyint [ FAILED ] math_h_force_long_double.lrint [ FAILED ] math_h_force_long_double.rint [ FAILED ] math_h_force_long_double.nearbyint ``` - lrint:执行单元测试 math_h.lrint 失败,期望返回 1235,但实际返回 1234,和 `rintl()` 函数有关, ```cpp ASSERT_EQ(1235, lrintl(1234.01L)); ``` - rint:失败在 `ASSERT_EQ(1235.0, rintl(1234.01L));` 所以原因和 lrint 的测试应该相同,也是和 `rintl()` 函数有关。 - nearbyint:失败在 `ASSERT_EQ(1235.0, nearbyintl(1234.01L));` 参考 `bionic/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c` ```cpp DECL(long double, nearbyintl, rintl) ``` 所以同样和 rintl 函数有关。 math_h_force_long_double 同 math_h,参考 `bionic/tests/math_force_long_double_test.cpp` ```cpp #define __BIONIC_LP32_USE_LONG_DOUBLE #include "math_test.cpp" ``` # 2. lrintl 函数分析 ## 2.1 32 位平台 参考 `bionic/libm/fake_long_double.c` ```cpp #if !defined(__LP64__) ...... #if !defined(__i386__) // x86 has an assembler lrint/lrintl. long lrintl(long double a1) { return lrint(a1); } #endif ... #endif // __LP64__ ``` 在 32 位平台下,x86 提供了汇编代码实现的 lrint/lrintl,其他的平台则采用 lrint 代替。但我们目前调试的是 riscv64 所以暂时不管 32 位平台的问题。 ## 2.2 64 位平台 实现参考 `bionic/libm/upstream-freebsd/lib/msun/src/s_lrintl.c` ```cpp #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); #define type long double #define roundit rintl #define dtype long #define fn lrintl #include "s_lrint.c" ``` 代入宏后展开最终内部实现指向的是 `rintl()`, 实现在 `bionic/libm/upstream-freebsd/lib/msun/src/s_rintl.c` 所以 lrintl 函数最终实际调用 `rintl()`, 抽取代码后源码见 <https://compiler-explorer.com/z/59TcePcvE>, 类似代码在 gcc 环境下测试 pass。 调试后发现 clang 编译环境下, 执行 `x += shift[sign];` 这句出现问题。 反汇编后如下: ```cpp 0x000000000047d06e <rintl+76>: 93 1a 25 00 slli s5,a0,0x2 0x000000000047d072 <rintl+80>: 17 25 bd ff auipc a0,0xffbd2 0x000000000047d076 <rintl+84>: 13 05 65 99 addi a0,a0,-1642 # 0x4ea08 <shift> 0x000000000047d07a <rintl+88>: 56 95 add a0,a0,s5 0x000000000047d07c <rintl+90>: 07 25 05 00 flw fa0,0(a0) 0x000000000047d080 <rintl+94>: 97 00 07 00 auipc ra,0x70 0x000000000047d084 <rintl+98>: e7 80 e0 76 jalr 1902(ra) # 0x4ed7ee <__extendsftf2> 0x000000000047d088 <rintl+102>: 2a 89 mv s2,a0 0x000000000047d08a <rintl+104>: ae 89 mv s3,a1 0x000000000047d08c <rintl+106>: 5e 86 mv a2,s7 0x000000000047d08e <rintl+108>: a2 86 mv a3,s0 0x000000000047d090 <rintl+110>: 97 f0 06 00 auipc ra,0x6f 0x000000000047d094 <rintl+114>: e7 80 e0 6a jalr 1710(ra) # 0x4ec73e <__addtf3> ``` 单步调试发现执行 0x000000000047d094 即调用 __addtf3 时返回的结果和 gcc 下的不同, 导致最后结果出错。 gcc 返回的 a0 = 0x00000000000004d3,a1 = 0x406f000000000000 clang 返回的 a0 = 0x00000000000004d2,a1 = 0x406f000000000000 所以我初步猜测,汇编的结果没有问题,出错是在调用 __addtf3 的实现有问题。
评论 (
6
)
登录
后才可以发表评论
状态
已完成
待办的
进行中
已完成
已关闭
负责人
未设置
陆旭凡
lu-xufan
负责人
协作者
+负责人
+协作者
标签
bug
未设置
标签管理
里程碑
未关联里程碑
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
分支 (
-
)
标签 (
-
)
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(2)
1
https://gitee.com/aosp-riscv/working-group.git
git@gitee.com:aosp-riscv/working-group.git
aosp-riscv
working-group
working-group
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册