简体   繁体   English

野牛和 avr-g++ 的双倍幂的精度

[英]Precision of a power of double in bison and avr-g++

I am writing a calculator for an avr microcontroller using bison and I have a problem with the resolution of a power of 2 doubles.我正在使用bisonavr微控制器编写计算器,但我对 2 次幂的分辨率有问题。

In my bison file I define the type as在我的bison文件中,我将类型定义为

    %define api.value.type {double}
    %token NUMBER

and then give the following rule然后给出以下规则

expr: NUMBER
     | expr '^' expr {$$ = pow($1, $3);}

And the code works properly except when I try to calculate 2^8 that gives me 255.9999 as the answer instead of 256 .并且代码正常工作,除非我尝试计算2^8给出的答案是255.9999而不是256

To see if the problem is with double or with pow I have modified the code this way:要查看问题出在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!!!!
                     }

As you can see the function pow works ok with a and b , and these two variables have the same value that $1 and $3 but $$ is different from c = pow(a, b) .如您所见,函数powab一起工作正常,这两个变量的值与$1$3相同,但$$c = pow(a, b)

I don't know what is happening.我不知道发生了什么。

Its the first time I use bison so most probably I've done something wrong.这是我第一次使用bison所以很可能我做错了什么。

I am compiling with avr-g++ 9.2.0.我正在使用 avr-g++ 9.2.0 进行编译。

Thanks.谢谢。


Edit: To see what is happening I've modified my rule in two different ways:编辑:为了查看发生了什么,我以两种不同的方式修改了我的规则:

If I try:如果我尝试:

expr: NUMBER
     | expr '^' expr {yyval = pow(2.0, 8.0);}

it gives me the right answer and print 256 .它给了我正确的答案并打印256

But instead if I try:但是,如果我尝试:

expr: NUMBER
     | expr '^' expr {yyval = pow($1, $3);}

it gives me the wrong answer 255.9999它给了我错误的答案255.9999

This has nothing to do with bison.这与野牛无关。 The culprit is the math library on the AVR microcontroller.罪魁祸首是 AVR 微控制器上的数学库。

When you write (in C):当你写(在 C 中):

double a = 2.0;
double b = 8.0;
double c = pow(a, b);

Gcc is smart enough to figure out that c will be 256.0. Gcc 足够聪明,可以确定 c 将是 256.0.0。 it's not necessary to do that computation at run time.没有必要在运行时进行该计算。 Gcc just rewrites that to double c = 256.0; Gcc 只是将其重写为double c = 256.0; . .

Gcc does that computation using the math library on the machine it is running on, or with its own bundled math library. Gcc 使用它运行的机器上的数学库或使用它自己的捆绑数学库来进行计算。 That's likely to be the Gnu math library, which optimises the computation of small integer powers.这很可能是 Gnu 数学库,它优化了小整数幂的计算。

The other call to pow is computed at runtime, because the compiler can't know what $1 and $3 are going to be.pow的另一个调用是在运行时计算的,因为编译器不知道$1$3将是什么。 So that call is done with the math library on the microcontroller, which is very slightly inaccurate.所以这个调用是通过微控制器上的数学库完成的,这有点不准确。 (It might do something like exp(8.0 * log(2.0)) , which introduces a small round-off error.) (它可能会做类似exp(8.0 * log(2.0))事情,这会引入一个小的舍入误差。)

One possible solution would be to write your own implementation of pow , which uses a more precise computation when the exponent is an integer.一种可能的解决方案是编写您自己的pow实现,当指数为整数时,它使用更精确的计算。

avr-gcc double is 32 bits per default. avr-gcc double 默认为 32 位。 For 64-bit double you'll need avr-gcc v10+, cf.对于 64 位双精度,您需要 avr-gcc v10+,参见。 the GCC release notes GCC 发行说明

https://gcc.gnu.org/gcc-10/changes.html#avr https://gcc.gnu.org/gcc-10/changes.html#avr

https://gcc.gnu.org/wiki/avr-gcc#Libf7 https://gcc.gnu.org/wiki/avr-gcc#Libf7

The rounding and precision issues inherent to floating-point numbers will still be there, though.不过,浮点数固有的舍入和精度问题仍然存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM