roundq 函式的 BUG
GCC 支援 __float128
型別,最大可表示約 104932 的浮點數,精度可達 33 位有效數字。但是,GCC Quad-Precision Math Library 中的 roundq
函式有 BUG:
roundq
: round-to-nearest integral value, return__float128
下面就是測試程式(roundq-bug.c):
#include <stdio.h>
#include <quadmath.h>
void test(__float128 x)
{
printf(" x: %f\n", (double)x);
printf("roundq: %f\n", (double)roundq(x));
printf("\n");
}
int main(void)
{
test(2147483647.6);
test(2147483648.6);
}
這個程式的執行結果如下所示:
$ gcc roundq-bug.c -lquadmath && ./a.out
x: 2147483647.600000 roundq: 2147483648.000000 x: 2147483648.600000 roundq: 2147483648.600000
使用的 gcc 版本如下所示:
$ gcc --version
gcc (GCC) 7.1.1 20170621
Copyright © 2017 Free Software Foundation, Inc.
本程式是自由軟體;請參看原始碼的版權宣告。本軟體沒有任何擔保;
包括沒有適銷性和某一專用目的下的適用性擔保。
從 roundq.c 編譯
把參考資料6和參考資料7中的 roundq.c 和 quadmath-imp.h 兩個檔案放到當前目錄,然後註釋掉 quadmath-imp.h 的第 27 行,再使用以下命令編譯和執行(即把 -lquadmath 替換為 roundq.c):
$ gcc roundq-bug.c roundq.c && ./a.out
得到的結果也是一樣的。然後就可以著手修改 roundq.c,試圖修復這個 Bug。
修復 Bug
根據參考資料4第 18 樓 Jakub Jelinek 的 attachment 41744,已經修復了這個 Bug,但是沒有進行充分的測試。這個補丁可能要在 gcc 8.0 中釋出。
Jakub Jelinek 2017-07-13 12:19:33 UTC Comment 18
Created attachment 41744 [details]
gcc8-pr65757.patchHere is a full version, it compiles, no further testing so far.
I guess I can bootstrap/regtest it next, but don't have time for further
testing. Guess it would be nice to tweak glibc math testsuite to test
__float128 with it, I vaguely remember Tobias doing that years ago, but not sure
if he had any patches for that.
...
下面是經過整理後的正確的 roundq.c:
#include "quadmath-imp.h"
__float128 roundq(__float128 x)
{
uint64_t i1, i0;
GET_FLT128_WORDS64(i0, i1, x);
int32_t j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
if (j0 < 48) {
if (j0 < 0) {
i0 &= 0x8000000000000000ULL;
if (j0 == -1) i0 |= 0x3fff000000000000LL;
i1 = 0;
} else {
uint64_t i = 0x0000ffffffffffffLL >> j0;
if (((i0 & i) | i1) == 0) return x; // x is integral.
i0 += 0x0000800000000000LL >> j0;
i0 &= ~i;
i1 = 0;
}
} else if (j0 > 111) {
if (j0 == 0x4000) return x + x; // Inf or NaN.
else return x;
} else {
uint64_t i = -1ULL >> (j0 - 48);
if ((i1 & i) == 0) return x; // x is integral.
uint64_t j = i1 + (1LL << (111 - j0));
if (j < i1) i0 += 1;
i1 = j;
i1 &= ~i;
}
SET_FLT128_WORDS64(x, i0, i1);
return x;
}
下面是 quadmath-imp.h 中相關的(經過整理後的)內容:
// The Intel x86 and x86-64 series of processors use little-endian.
// Main union type we use to manipulate the floating-point type.
typedef union
{
__float128 value;
struct
{
uint64_t mant_low:64;
uint64_t mant_high:48;
unsigned exponent:15;
unsigned negative:1;
} ieee;
struct
{
uint64_t low;
uint64_t high;
} words64;
struct
{
uint32_t w3;
uint32_t w2;
uint32_t w1;
uint32_t w0;
} words32;
struct
{
uint64_t mant_low:64;
uint64_t mant_high:47;
unsigned quiet_nan:1;
unsigned exponent:15;
unsigned negative:1;
} nan;
} ieee854_float128;
// Get two 64 bit ints from a long double.
#define GET_FLT128_WORDS64(ix0,ix1,d) \
do { \
ieee854_float128 u; \
u.value = (d); \
(ix0) = u.words64.high; \
(ix1) = u.words64.low; \
} while (0)
// Set a long double from two 64 bit ints.
#define SET_FLT128_WORDS64(d,ix0,ix1) \
do { \
ieee854_float128 u; \
u.words64.high = (ix0); \
u.words64.low = (ix1); \
(d) = u.value; \
} while (0)
編譯和執行:
$ gcc roundq-bug.c roundq.c && ./a.out
x: 2147483647.600000 roundq: 2147483648.000000 x: 2147483648.600000 roundq: 2147483649.000000
執行結果是正確的。
參考資料
相關文章
- oracle interval日期函式的bug!Oracle函式
- [20191002]函式dump的bug.txt函式
- [BUG反饋]除錯模式下函式U()的BUG除錯模式函式
- MySQL 對window函式執行sum函式疑似BugMySql函式
- PHP原始碼分析-函式array_merge的”BUG”PHP原始碼函式
- [BUG反饋]get_cover函式相關函式
- [BUG反饋]模型屬性自定義函式提交不了模型函式
- main函式的入口函式AI函式
- 箭頭函式、簡寫函式、普通函式的區別函式
- MySQL函式大全(字串函式,數學函式,日期函式,系統級函式,聚合函式)MySql函式字串
- Sql 中的 left 函式、right 函式SQL函式
- 閉包函式(匿名函式)的理解函式
- Rust中的into函式和from函式Rust函式
- 函式: 函式是怎麼使用的?函式
- python內建函式-eval()函式與exec()函式的區別Python函式
- python中id()函式、zip()函式、map()函式、lamda函式Python函式
- Python 擴充之特殊函式(lambda 函式,map 函式,filter 函式,reduce 函式)Python函式Filter
- JavaScript中的compose函式和pipe函式JavaScript函式
- 函式外與函式內的變數函式變數
- ton函式函式hash的兩種形式函式
- strcpy函式和memcpy函式的區別函式memcpy
- 類的建構函式和解構函式函式
- 如何使用函式指標呼叫類中的函式和普通函式函式指標
- 【譯】函式式的React函式React
- JavaScript的迭代函式與迭代函式的實現JavaScript函式
- 第7章 IF函式 COUNTIF函式 SUMIF函式函式
- MySQL(四)日期函式 NULL函式 字串函式MySql函式Null字串
- 【不在混淆的C】指標函式、函式指標、回撥函式指標函式
- (譯) 函式式 JS #2: 函式!函式JS
- 建構函式與普通函式的區別函式
- 箭頭函式與普通函式的區別函式
- # 普通函式和箭頭函式的區別函式
- PHP 函式庫 1 - 函式庫的分類PHP函式
- 平凡的函式 線性篩積性函式函式
- 函式的祕密之 函式返回值函式
- [BUG反饋]OneThink版本 1.1.141101版本Bug:模型自動驗證和自動完成函式有衝突模型函式
- 核函式 多項式核函式 高斯核函式(常用)函式
- 第 8 節:函式-匿名函式、遞迴函式函式遞迴
- TypeScript 中函式的理解?與 JavaScript 函式的區別?TypeScript函式JavaScript