user-0 提问: VS2019数学函数计算有错误

回复:
user: user-1
content: 寻开心大哥是高手，还是他来讲吧。

user: user-2
content: 引用 33 楼 luj_1768 的回复:哎呀，有效数据有关的事，看上去大家不太懂。总有效数字是18位，简化计算有效位是16位，如果能得到后三位的有效数字，可以通过校正算法获得全部数位的精确值。 给讲一下吗？

user: user-1
content: 哎呀，有效数据有关的事，看上去大家不太懂。总有效数字是18位，简化计算有效位是16位，如果能得到后三位的有效数字，可以通过校正算法获得全部数位的精确值。

user: user-3
content: 高精度就用bigdecimal类来处理

user: user-4
content: 一入程序深似海

user: user-5
content: 过来看看哈哈哈

user: user-6
content: 引用 2 楼 liups的回复:函数库通常是不会有错误的，就算有，通常也不是楼主能发现的 有道理啊 不过有时候运气

user: user-6
content: 引用 楼主 要上天的拉布拉多的回复:VS里边的math函数库的pow函数，似乎有错误，当计算15的15次方时，计算结果的后三位是不对的。 这个不是废话吗？高精度计算有专门的库的

user: user-7
content: 应该是溢出了，有一个大数计算的例子，供参考～  #include <stdio.h> #include <stdlib.h> #include <string.h>  #define MAX_NUM_LEN 2048  int cal_factorial(unsigned char *num_list, int num_size, int n);  int cal_val(unsigned char *num_list, int num_size, int base, int num) {     int i = 0, j;     int len = 1, tmp, carry_bit;      num_list[1] = 1;      while (i < num) {         carry_bit = 0;         for (j = 1; j <= len; j++) {             tmp = num_list[j] * base + carry_bit;             num_list[j] = tmp % 10;             carry_bit = tmp / 10;             if (j >= len && carry_bit != 0)                 len++;             if (num_size-1 < len) {/* overflow */                 printf("Overflow!\n");                 return num_size-1;             }         }         i++;     }      return len; }   int main(void) {     unsigned char num_list[MAX_NUM_LEN];     int num_len, i;     int base, power;      memset(num_list, 0, sizeof(num_list));     printf("Please input two numbers: ");     scanf("%d%d", &base, &power);      if (base < 0 && power % 2)         num_list[0] = 1; /* negative number */     else         num_list[0] = 0;     base = abs(base);      num_len = cal_val(num_list, MAX_NUM_LEN, base, power);     printf("len = %d\n", num_len);     if (num_list[0])         putchar('-');     for (i = num_len; i >= 1; i--)         printf("%d", num_list[i]);     printf("\n");     return 0; }   int cal_factorial(unsigned char *num_list, int num_size, int n) {     int carry_bit, i, j, len = 1;     int tmp;      num_list[1] = 1;     for (i = 2; i <= n; i++)     {         carry_bit = 0;         for (j = 1; j <= len; j++) {             tmp = num_list[j] * i + carry_bit;             num_list[j] = tmp % 10;             carry_bit = tmp / 10;             if (j >= len && carry_bit != 0)                 len++;             if (num_size -1 < len) { /* overflow */                 printf("Overflow!\n");                 return num_size-1;             }         }      }      /*     for (i = len; i >= 1; i--)//逆序输出数组就是结果         printf("%d", a[i]);     printf("\n");     */     return len; } 供参考～

user: user-2
content: 引用 24 楼 早打大打打核战争 的回复:[quote=引用 15 楼 liups 的回复:] [quote=引用 14 楼 早打大打打核战争 的回复:] [quote=引用 13 楼 liups 的回复:] [quote=引用 12 楼 liups 的回复:] 或者说参数超出允许（能正确处理）的范围了。 当然，都只是个人推测 sin returns the sine of x. If x is greater than or equal to 2^63, or less than or equal to –2^63, a loss of significance in the result occurs, in which case the function generates a _TLOSS error and returns an indefinite (same as a quiet NaN).  以上引用自MSDN98（针对VC6.0的） 2的63次方大约是9.2233720368548e+18，所以这个不是BUG！是参数超出范围了。[/quote]  sin的输入参数是float/double/long double，如果输入整型会转换为浮点型，VC6的限制只能说是它自身的问题，不是理由，况且按这个说明。输入超出范围VC6会输出NaN，而不是一个错误结果。而且为什么别的编译器可以正确得出结果，VC++ 32位编译器不能？ [/quote] 我认为你这是牵强附会了！也许其他编译器能处理1e22，但是肯定也有其限制，不可能是随便输入什么都行的。[/quote]  输入范围−2^63 到 +2^63的限制实际来自于x86 FPU的fsin指令（注意C数学库的sin并没有写这个限制），但是intel文档上明确说了输入超过范围，st(0)保持未改变，也就是fsin(-1e22)应该输出-1e22，但是VC++ 32位编译器（实测VS2015）sin(-1e22)的结果既没有返回NaN，也不是-1e22，而是一个错误值-0.4121434 [/quote] 学习了

user: user-8
content: 顶一下dddddddddddsss

user: user-9
content: 是你写错了吧

user: user-10
content: 引用 15 楼 liups 的回复:[quote=引用 14 楼 早打大打打核战争 的回复:] [quote=引用 13 楼 liups 的回复:] [quote=引用 12 楼 liups 的回复:] 或者说参数超出允许（能正确处理）的范围了。 当然，都只是个人推测 sin returns the sine of x. If x is greater than or equal to 2^63, or less than or equal to –2^63, a loss of significance in the result occurs, in which case the function generates a _TLOSS error and returns an indefinite (same as a quiet NaN).  以上引用自MSDN98（针对VC6.0的） 2的63次方大约是9.2233720368548e+18，所以这个不是BUG！是参数超出范围了。[/quote]  sin的输入参数是float/double/long double，如果输入整型会转换为浮点型，VC6的限制只能说是它自身的问题，不是理由，况且按这个说明。输入超出范围VC6会输出NaN，而不是一个错误结果。而且为什么别的编译器可以正确得出结果，VC++ 32位编译器不能？ [/quote] 我认为你这是牵强附会了！也许其他编译器能处理1e22，但是肯定也有其限制，不可能是随便输入什么都行的。[/quote]  输入范围−2^63 到 +2^63的限制实际来自于x86 FPU的fsin指令（注意C数学库的sin并没有写这个限制），但是intel文档上明确说了输入超过范围，st(0)保持未改变，也就是fsin(-1e22)应该输出-1e22，但是VC++ 32位编译器（实测VS2015）sin(-1e22)的结果既没有返回NaN，也不是-1e22，而是一个错误值-0.4121434

user: user-11
content: 精度问题，不算BUG

user: user-12
content: 很难很深奥~大家是在学术研究还是解决实际问题？

user: user-13
content: 精度问题。通常这种情况，直接用py就没有任何问题了，py支持任意大的整数。用C还得自己构造大整数，麻烦。

user: user-14
content: 有资料吗，我也是有想往软件方面靠

user: user-15
content: 要是能正确就不正常了， 15^15 的结果本来就没法用 double 精确表示，不信的话你可以手动把 15^15 算出来赋给一个 double，然后 printf 一下试试。

user: user-2
content: 15^15是4.3789389038086e+17 而MSDN中查询得知： pow does not recognize integral floating-point values greater than 2^64, such as 1.0E100.  2的64次方是1.844674407371e+19  没有溢出！

user: user-0
content: 我也想过溢出的问题，pow函数求15^15只是最后两位不对，但是16^16又是对的