2013-11-27 191 views
2

我花了幾個小時來調試這個問題,並最終自己解決了這個問題。以爲我會在這裏發佈,以防止其他人遇到同樣的荒謬問題。Arduino - 具有pow(x,y)函數的奇數指數行爲

我肯定會對打開一個更深的解釋,爲什麼我的回答是一個解釋。


我一直在使用pow(x,y)函數返回指數。我注意到指數非常奇怪,我不明白爲什麼。這裏是我的代碼:

for (int n=0;n<5;n++) 
{ 
    int x = pow(2,n); 
    Serial.print(n); 
    Serial.print(" "); 
    Serial.println(x); 
} 

這是我的輸出:

0 1 
1 2 
2 3 
3 7 
4 15 

所以這些數字顯然是不正確的。奇怪的是,當我在C運行相同的代碼在Xcode ++程序(與COUT語句,而不是串行輸出)我得到以下(這是我所期望的):

0 1 
1 2 
2 4 
3 8 
4 16 

爲什麼在世界上會這種回報我在Xcode的期望值,但不是在Arduino上?爲什麼arduino返回pow(2,n) = 2^n-1任何值n大於1?

+0

您的意思是使用'1 << N'? –

+0

不確定你的意思。我的意思是使用大的n值嗎? No. –

+2

我的意思是'(int)pow(2,n)'是不應該寫的東西。 'pow'是用於浮點的。 C++有'運營商<<',其中'1 << N'給出了2 –

回答

3

啊,你這個少年笨蛋,瑞恩!你有沒有理解數據類型!?

The Arduino pow() reference明確指出這些值必須作爲浮點數傳遞並作爲雙精度返回!所以讓我們使用一些腦細胞,至少嘗試返回一個雙倍!

下面是一些代碼來突出這回事瘋狂:

for (int n=0;n<5;n++) 
{ 
    double x = pow(2,n); 
    Serial.print(n); 
    Serial.print(" "); 
    Serial.print(x); 
    Serial.print(" "); 
    Serial.println((int)x); // cast as int here 
} 

而且這裏是你的輸出:

0 1.00 1 
1 2.00 2 
2 4.00 3 
3 8.00 7 
4 16.00 15 

無論如何,這將解決您的問題。將數字轉換爲int表明它被舍入。


現在,爲什麼會發生這種情況?不完全確定。

+1

的n次冪,取整,你可以投之前使用'nearbyint','rint','round'等。 –

+0

我沒有意識到這一點。謝謝你的提示。 –

+0

返回值取決於如何實現'pow'函數。它接收2個double值,所以它可能因整數指數計算pow(x,y)= exp(x * ln(y))的方式而不正確地工作。而你獲得2的權力的方式只是「錯誤的」。 '1個<< y'是幾百倍'POW快(2,y)的'上的8位微控制器 –

4

由於AVR沒有FPU,所以在avr-libc中的pow()通過調用log()exp()來實現。同樣,由於缺乏FPU,avr-libc對這兩種功能都使用近似值。這會導致與真實值稍微偏離的值,當將其轉換爲整數時,可能會丟失最不重要的數字。

這在x86級系統上不會發生,因爲那些硬件FPU能夠爲正整數的非負冪賦予真正的整數值。

我的建議是,如果你所需要的是整數的非負整數冪,那麼你應該執行一系列的按位移並添加,而不是必須鏈接在非平凡的,非確切的libm

-1

老問題,但對於未來的提問者:

理由16.0四捨五入到15,是從浮到INT的轉換總是被截斷小數。所以15.99999仍然成爲15和16不會

由於浮點值不能精確包含16.0,他們持有類似15.99963513(隨便舉個例子),其在鑄造到一個整數變成15。

+0

您寫道:「_floating點值不能精確包含16.0_」。是的他們可以。 –

0

只是作爲一種補充伊格納西奧巴斯克斯 - 艾布拉姆斯答案(這是 正確的答案),我寫了下面的程序來測試的 pow(2, i)爲正整數精度i

#include <stdio.h> 
#include <math.h> 
#include <float.h> 
#include <inttypes.h> 

int main(void) 
{ 
    printf(" i   2^i  correct pow(2, i)   error ulps\n"); 
    printf("------------------------------------------------------------\n"); 
    union { float f; uint32_t i; } x, y; 
    x.f = 1;     // 2^i, correct value 
    float ulp_r = FLT_EPSILON; // ULP to the right of x 
    for (int i = 0; i < 128; i++, x.f *= 2, ulp_r *= 2) { 
     y.f = pow(2, i); 
     float error = y.f - x.f; 
     float ulp = error < 0 ? ulp_r/2 : ulp_r; // ULP(x - error) 
     printf("%3d %11.6g 0x%08"PRIx32" 0x%08"PRIx32" %12.6g %4g\n", 
       i, x.f, x.i, y.i, error, error/ulp); 
    } 
    return 0; 
} 

在我的電腦上(gcc 5.4.0/Ubuntu 16.04),這個程序報告零錯誤。 在Arduino Uno (avr-gcc 4.9.2/avr-libc 1.8.0)上運行相同的程序(通過正確的stdio設置),我得到的差錯大到 ULPs!下面是從歐諾輸出:

i   2^i  correct pow(2, i)   error ulps 
------------------------------------------------------------ 
    0   1 0x3f800000 0x3f800000    0  0 
    1   2 0x40000000 0x40000000    0  0 
    2   4 0x40800000 0x407ffffe -4.76837e-07 -2 
    3   8 0x41000000 0x40fffffc -1.90735e-06 -4 
    4   16 0x41800000 0x417ffffc -3.8147e-06 -4 
    5   32 0x42000000 0x41fffffa -1.14441e-05 -6 
    6   64 0x42800000 0x427ffffa -2.28882e-05 -6 
    7   128 0x43000000 0x42fffffa -4.57764e-05 -6 
    8   256 0x43800000 0x437ffffa -9.15527e-05 -6 
    9   512 0x44000000 0x43fffff4 -0.000366211 -12 
10   1024 0x44800000 0x447ffff4 -0.000732422 -12 
11   2048 0x45000000 0x44fffff4 -0.00146484 -12 
12   4096 0x45800000 0x457ffff4 -0.00292969 -12 
13   8192 0x46000000 0x46000000    0  0 
14  16384 0x46800000 0x467ffff4 -0.0117188 -12 
15  32768 0x47000000 0x46fffff4 -0.0234375 -12 
16  65536 0x47800000 0x477ffff4  -0.046875 -12 
17  131072 0x48000000 0x48000000    0  0 
18  262144 0x48800000 0x487fffea  -0.34375 -22 
19  524288 0x49000000 0x48ffffea  -0.6875 -22 
20 1.04858e+06 0x49800000 0x497fffea  -1.375 -22 
21 2.09715e+06 0x4a000000 0x4a000000    0  0 
22 4.1943e+06 0x4a800000 0x4a7fffea   -5.5 -22 
23 8.38861e+06 0x4b000000 0x4affffea   -11 -22 
24 1.67772e+07 0x4b800000 0x4b7fffea   -22 -22 
25 3.35544e+07 0x4c000000 0x4c000000    0  0 
26 6.71089e+07 0x4c800000 0x4c800000    0  0 
27 1.34218e+08 0x4d000000 0x4cffffea   -176 -22 
28 2.68435e+08 0x4d800000 0x4d7fffea   -352 -22 
29 5.36871e+08 0x4e000000 0x4e000000    0  0 
30 1.07374e+09 0x4e800000 0x4e7fffea   -1408 -22 
31 2.14748e+09 0x4f000000 0x4effffea   -2816 -22 
32 4.29497e+09 0x4f800000 0x4f7fffea   -5632 -22 
33 8.58993e+09 0x50000000 0x50000000    0  0 
34 1.71799e+10 0x50800000 0x50800000    0  0 
35 3.43597e+10 0x51000000 0x50ffffd2  -94208 -46 
36 6.87195e+10 0x51800000 0x517fffd2  -188416 -46 
37 1.37439e+11 0x52000000 0x52000000    0  0 
38 2.74878e+11 0x52800000 0x527fffd2  -753664 -46 
39 5.49756e+11 0x53000000 0x52ffffd2 -1.50733e+06 -46 
40 1.09951e+12 0x53800000 0x537fffd2 -3.01466e+06 -46 
41 2.19902e+12 0x54000000 0x54000000    0  0 
42 4.39805e+12 0x54800000 0x54800000    0  0 
43 8.79609e+12 0x55000000 0x54ffffd2 -2.41172e+07 -46 
44 1.75922e+13 0x55800000 0x557fffd2 -4.82345e+07 -46 
45 3.51844e+13 0x56000000 0x56000000    0  0 
46 7.03687e+13 0x56800000 0x567fffd2 -1.92938e+08 -46 
47 1.40737e+14 0x57000000 0x57000000    0  0 
48 2.81475e+14 0x57800000 0x577fffd2 -7.71752e+08 -46 
49 5.6295e+14 0x58000000 0x57ffffd2 -1.5435e+09 -46 
50 1.1259e+15 0x58800000 0x58800000    0  0 
51 2.2518e+15 0x59000000 0x58ffffd2 -6.17402e+09 -46 
52 4.5036e+15 0x59800000 0x59800000    0  0 
53 9.0072e+15 0x5a000000 0x5a000000    0  0 
54 1.80144e+16 0x5a800000 0x5a7fffd2 -4.93921e+10 -46 
55 3.60288e+16 0x5b000000 0x5b000000    0  0 
56 7.20576e+16 0x5b800000 0x5b7fffd2 -1.97568e+11 -46 
57 1.44115e+17 0x5c000000 0x5bffffd2 -3.95137e+11 -46 
58 2.8823e+17 0x5c800000 0x5c800000    0  0 
59 5.76461e+17 0x5d000000 0x5cffffd2 -1.58055e+12 -46 
60 1.15292e+18 0x5d800000 0x5d7fffd2 -3.1611e+12 -46 
61 2.30584e+18 0x5e000000 0x5e000000    0  0 
62 4.61169e+18 0x5e800000 0x5e7fffd2 -1.26444e+13 -46 
63 9.22337e+18 0x5f000000 0x5f000000    0  0 
64 1.84467e+19 0x5f800000 0x5f7fffd2 -5.05775e+13 -46 
65 3.68935e+19 0x60000000 0x5fffffa6 -1.97912e+14 -90 
66 7.3787e+19 0x60800000 0x60800000    0  0 
67 1.47574e+20 0x61000000 0x60ffffa6 -7.91648e+14 -90 
68 2.95148e+20 0x61800000 0x61800000    0  0 
69 5.90296e+20 0x62000000 0x61ffffa6 -3.16659e+15 -90 
70 1.18059e+21 0x62800000 0x627fffa6 -6.33319e+15 -90 
71 2.36118e+21 0x63000000 0x63000000    0  0 
72 4.72237e+21 0x63800000 0x637fffa6 -2.53327e+16 -90 
73 9.44473e+21 0x64000000 0x63ffffa6 -5.06655e+16 -90 
74 1.88895e+22 0x64800000 0x64800000    0  0 
75 3.77789e+22 0x65000000 0x64ffffa6 -2.02662e+17 -90 
76 7.55579e+22 0x65800000 0x657fffa6 -4.05324e+17 -90 
77 1.51116e+23 0x66000000 0x65ffffa6 -8.10648e+17 -90 
78 3.02231e+23 0x66800000 0x667fffa6 -1.6213e+18 -90 
79 6.04463e+23 0x67000000 0x67000000    0  0 
80 1.20893e+24 0x67800000 0x677fffa6 -6.48518e+18 -90 
81 2.41785e+24 0x68000000 0x67ffffa6 -1.29704e+19 -90 
82 4.8357e+24 0x68800000 0x68800000    0  0 
83 9.67141e+24 0x69000000 0x68ffffa6 -5.18815e+19 -90 
84 1.93428e+25 0x69800000 0x69800000    0  0 
85 3.86856e+25 0x6a000000 0x69ffffa6 -2.07526e+20 -90 
86 7.73713e+25 0x6a800000 0x6a7fffa6 -4.15052e+20 -90 
87 1.54743e+26 0x6b000000 0x6b000000    0  0 
88 3.09485e+26 0x6b800000 0x6b7fffa6 -1.66021e+21 -90 
89 6.1897e+26 0x6c000000 0x6bffffa6 -3.32041e+21 -90 
90 1.23794e+27 0x6c800000 0x6c800000    0  0 
91 2.47588e+27 0x6d000000 0x6cffffa6 -1.32817e+22 -90 
92 4.95176e+27 0x6d800000 0x6d7fffa6 -2.65633e+22 -90 
93 9.90352e+27 0x6e000000 0x6dffffa6 -5.31266e+22 -90 
94 1.9807e+28 0x6e800000 0x6e800000    0  0 
95 3.96141e+28 0x6f000000 0x6f000000    0  0 
96 7.92282e+28 0x6f800000 0x6f7fffa6 -4.25013e+23 -90 
97 1.58456e+29 0x70000000 0x6fffffa6 -8.50026e+23 -90 
98 3.16913e+29 0x70800000 0x707fffa6 -1.70005e+24 -90 
99 6.33825e+29 0x71000000 0x71000000    0  0 
100 1.26765e+30 0x71800000 0x71800000    0  0 
101 2.5353e+30 0x72000000 0x71ffffa6 -1.36004e+25 -90 
102 5.0706e+30 0x72800000 0x727fffa6 -2.72008e+25 -90 
103 1.01412e+31 0x73000000 0x72ffffa6 -5.44017e+25 -90 
104 2.02824e+31 0x73800000 0x73800000    0  0 
105 4.05648e+31 0x74000000 0x74000000    0  0 
106 8.11296e+31 0x74800000 0x74800000    0  0 
107 1.62259e+32 0x75000000 0x74ffffa6 -8.70427e+26 -90 
108 3.24519e+32 0x75800000 0x757fffa6 -1.74085e+27 -90 
109 6.49037e+32 0x76000000 0x75ffffa6 -3.48171e+27 -90 
110 1.29807e+33 0x76800000 0x76800000    0  0 
111 2.59615e+33 0x77000000 0x77000000    0  0 
112 5.1923e+33 0x77800000 0x777fffa6 -2.78537e+28 -90 
113 1.03846e+34 0x78000000 0x77ffffa6 -5.57073e+28 -90 
114 2.07692e+34 0x78800000 0x787fffa6 -1.11415e+29 -90 
115 4.15384e+34 0x79000000 0x79000000    0  0 
116 8.30767e+34 0x79800000 0x79800000    0  0 
117 1.66153e+35 0x7a000000 0x79ffffa6 -8.91317e+29 -90 
118 3.32307e+35 0x7a800000 0x7a7fffa6 -1.78263e+30 -90 
119 6.64614e+35 0x7b000000 0x7affffa6 -3.56527e+30 -90 
120 1.32923e+36 0x7b800000 0x7b7fffa6 -7.13053e+30 -90 
121 2.65846e+36 0x7c000000 0x7c000000    0  0 
122 5.31691e+36 0x7c800000 0x7c800000    0  0 
123 1.06338e+37 0x7d000000 0x7cffffa6 -5.70443e+31 -90 
124 2.12676e+37 0x7d800000 0x7d7fffa6 -1.14089e+32 -90 
125 4.25353e+37 0x7e000000 0x7dffffa6 -2.28177e+32 -90 
126 8.50706e+37 0x7e800000 0x7e800000    0  0 
127 1.70141e+38 0x7f000000 0x7f000000    0  0 

有幾點值得注意:

  • FLT_MAX兩者之間FLT_MIN每次開機正是 表示爲一個float
  • 的IEEE-754標準需要操作+, - ,×,÷和√是 正確的舍入,這意味着2 通過 計算我迭代multiplyin通過2克保證得到精確的結果
  • 同一標準並要求pow被正確地舍入。