我花了几个小时调试这个问题,最终自己解决了。以为我会在这里发布,以防止其他人遇到同样荒谬的问题。
对于为什么我的回答是一个解释,我肯定愿意接受更深入的解释。
我一直在使用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
所以这些数字显然不对。奇怪的是,当我在Xcode中的C ++程序中运行相同的代码(使用cout语句而不是串行输出)时,我得到以下内容(我期望):
0 1
1 2
2 4
3 8
4 16
为什么世界会在Xcode中返回我的预期值而不是在arduino上?为什么arduino会为{em> n 大于1的值返回pow(2,n) = 2^n-1
?
答案 0 :(得分:4)
由于AVR没有FPU,avr-libc中的pow()
是通过调用log()
和exp()
实现的。同样,由于缺少FPU,avr-libc对这两个函数使用近似。这会导致值与真值稍微偏离,当转换为整数时,可能会丢失最低有效数字。
这在x86级系统上不会发生,因为它们具有硬件FPU,能够为正整数的非负幂提供真正的积分值。
我的建议是,如果您需要的只是整数的非负整数幂,那么您应该执行一系列按位移位并添加而不是必须链接到非平凡的非精确libm
。
答案 1 :(得分: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表示它向下舍入。
现在,为什么会这样?不太确定。
答案 2 :(得分:0)
正如Ignacio Vazquez-Abrams的答案(这是
正确答案),我编写了以下程序来测试其准确性
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上运行相同的程序(使用适当的stdio设置) (avr-gcc 4.9.2 / avr-libc 1.8.0),我得到的错误一样大 90 ULPs!以下是Uno的输出:
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_MIN
和FLT_MAX
之间的每两个幂都是正确的
可表示为float
pow
正确舍入。答案 3 :(得分:-1)
老问题,但对于未来的问题:
将16.0向下舍入为15的原因是,从float到int的转换始终是截断小数。所以15.99999仍然是15而不是16。
由于浮点值不能精确地包含16.0,因此它们具有类似于15.99963513(随机示例)的内容,在转换为整数时变为15。