[英]Precision of a power of double in bison and avr-g++
我正在使用bison
為avr
微控制器編寫計算器,但我對 2 次冪的分辨率有問題。
在我的bison
文件中,我將類型定義為
%define api.value.type {double}
%token NUMBER
然后給出以下規則
expr: NUMBER
| expr '^' expr {$$ = pow($1, $3);}
並且代碼正常工作,除非我嘗試計算2^8
給出的答案是255.9999
而不是256
。
要查看問題出在double
還是pow
我已經這樣修改了代碼:
expr: NUMBER
| expr '^' expr {$$ = pow($1, $3);
double a = 2.0; double b = 8.0;
if (a == $1) lcd << "a ok"; // prints ok
if (b == $3) lcd << "b ok"; // prints ok
double c = pow(a, b);
lcd << c; // it shows 256!!!
if ($$ == c) lcd << "$$ ok";
else lcd << "$$ wrong"; // prints wrong!!!!
}
如您所見,函數pow
與a
和b
一起工作正常,這兩個變量的值與$1
和$3
相同,但$$
與c = pow(a, b)
。
我不知道發生了什么。
這是我第一次使用bison
所以很可能我做錯了什么。
我正在使用 avr-g++ 9.2.0 進行編譯。
謝謝。
編輯:為了查看發生了什么,我以兩種不同的方式修改了我的規則:
如果我嘗試:
expr: NUMBER
| expr '^' expr {yyval = pow(2.0, 8.0);}
它給了我正確的答案並打印256
。
但是,如果我嘗試:
expr: NUMBER
| expr '^' expr {yyval = pow($1, $3);}
它給了我錯誤的答案255.9999
這與野牛無關。 罪魁禍首是 AVR 微控制器上的數學庫。
當你寫(在 C 中):
double a = 2.0;
double b = 8.0;
double c = pow(a, b);
Gcc 足夠聰明,可以確定 c 將是 256.0.0。 沒有必要在運行時進行該計算。 Gcc 只是將其重寫為double c = 256.0;
.
Gcc 使用它運行的機器上的數學庫或使用它自己的捆綁數學庫來進行計算。 這很可能是 Gnu 數學庫,它優化了小整數冪的計算。
對pow
的另一個調用是在運行時計算的,因為編譯器不知道$1
和$3
將是什么。 所以這個調用是通過微控制器上的數學庫完成的,這有點不准確。 (它可能會做類似exp(8.0 * log(2.0))
事情,這會引入一個小的舍入誤差。)
一種可能的解決方案是編寫您自己的pow
實現,當指數為整數時,它使用更精確的計算。
avr-gcc double 默認為 32 位。 對於 64 位雙精度,您需要 avr-gcc v10+,參見。 GCC 發行說明
https://gcc.gnu.org/gcc-10/changes.html#avr
https://gcc.gnu.org/wiki/avr-gcc#Libf7
不過,浮點數固有的舍入和精度問題仍然存在。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.