无法弄清楚C中pow()函数的计算

Rak*_*lam 1 c floating-point math.h pow

今天,我发现了一些我不知道的奇怪计算(在SO中也没有发现任何关于此的问题)关于C.的pow()功能math.h.

我正在试验的代码是:

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

int main(){
    //1st case
    long long result = pow(2, 63);
    printf("1st case: %lld\n", result);

    //2nd case
    result = pow(2, 64);
    printf("2nd case: %lld\n", result);

    //3rd case
    printf("3rd case: %lld\n", (long long) (pow(2, 64)/12000));

    //4th case
    result = pow(2, 64);
    result = result/12000;
    printf("4th case: %lld\n", result);

    //5th case
    result = pow(2, 64) / 12000;
    printf("5th case: %lld\n", result); 

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

1st case: 9223372036854775807
2nd case: 9223372036854775807
3rd case: 1537228672809129
4th case: 768614336404564
5th case: 1537228672809129
Run Code Online (Sandbox Code Playgroud)

我有几个问题,我不清楚.我正在使用CodeBlocks 16.01 IDE和GNU GCC编译器.

1.在第一种情况下,输出是,2^63 = 9223372036854775807.为什么会这样?这里的最后一位数字很奇怪.它应该是9223372036854775808.

2.在第二种情况下,2^64 = 9223372036854775807它与先前计算的相同2^63(实际上,对于任何大于63的指数值,这是相同的).是的,我知道long long int数据类型会出现溢出.但为什么分配了错误的值?

3.在第3例和第5例(实际上相同)中,答案是正确的.但在第四种情况下,答案是错误的.根据算术运算,第四种情况下的数学运算应与其余两种情况相同,但实际上并非如此.然后差异在哪里?

gsa*_*ras 6

这些警告(编译得像gcc prog.c -Wall -Wextra)对你来说不够吗?

prog.c: In function 'main':
prog.c:6:24: warning: overflow in conversion from 'double' to 'long long int' changes value from '(double)9.2233720368547758e+18' to '9223372036854775807' [-Woverflow]
     long long result = pow(2, 63);
                        ^~~
prog.c:10:14: warning: overflow in conversion from 'double' to 'long long int' changes value from '(double)1.8446744073709552e+19' to '9223372036854775807' [-Woverflow]
     result = pow(2, 64);
              ^~~
prog.c:17:14: warning: overflow in conversion from 'double' to 'long long int' changes value from '(double)1.8446744073709552e+19' to '9223372036854775807' [-Woverflow]
     result = pow(2, 64);
              ^~~
Run Code Online (Sandbox Code Playgroud)

我的意思是溢出发生,然后舍入发生,这给你这个输出,因为实际值根本不适合该数据类型.如果它是一个long double,事情会有所不同.(别忘了打印%Lf.)

阅读更多内容导致浮点舍入错误的原因什么?


PS:在情况3中你在转换之前进行除法long long,因此它使用浮点值,这是正确的,正如Barmar正确评论的那样.

  • 也许OP忽略了那些警告 - 努力的+1. (2认同)
  • @RakibulIslam在第3种情况下,你在转换为`long long`之前进行除法,因此它使用浮点值,这是正确的. (2认同)