Pandora Eartha的回答
不能把数学上的结论不加考虑地带到计算机来.
先回答你的这个问题, 再举一些常见的计算机数学特性.
这个泰勒展开式是完全正确的, 对一切 都收敛, 其实对虚数也收敛.
但是为什么带入 的时候, 计算值和理论值差这么多呢?
你这个函数输出的数据类型是 double , 那我们就来回忆一下 IEEE754标准中, 浮点数是怎么定义的.
浮点数是由数符S, 阶码E(移码表示), 尾数M 构成的.
对于在浮点数表示范围内的实数 , 有
, 在这里我们规定
.
类似我们的十进制科学技术法
例如
二进制浮点数类似.
对于双精度(64位)浮点数来说, 其阶码为 位, 且其阶码的偏置值是
所以其指数部分最大为
最小为 .
尾数部分是 位, 省略最高位, 所以其尾数部分最大为
最小为 .
这个结论告诉我们什么呢? 告诉我们, 浮点数的精度是有限的.
精度是 ?
不对, 精度是 , 这也意味着, 在浮点数表示范围中,
一个数的绝对值如果越大, 其精度就越低.
一个数的绝对值如果越小, 其精度就越高.
因此, 如果一个数非常非常大, 大到了 级别, 其精度最高也只能有
而如果一个数非常小, 其精度就可以达到
所以, 如果你的 取
, 甚至是
最后都会因为运算过程中数字太大而丢失精度.
那正确的做法是什么呢?
正确的做法是利用三角函数的周期性将数据都转换为 附近的数据.
比如说 可以转换为
进一步转换为
.
也就是说, 将所有数据都映射到 上.
OK, 那我们把你的代码改写一下.
先判断 是否为负数.
将 映射到
上
将 数据映射到
上.
映射到
上
import 泰勒展开
计算正确.
计算正确
能精确到小数点后
位.
计算正确
OK, 那我们见识一下常见的计算机特性.
<img src="https://www.zhihu.com/equation?tex=%5Cbegin%7Balign%7D+%26%5Ctext%7Bint%7D%5C+%5C+A%3D2147483647%5C%5C+%26A%2B1%3D-2147483648%5C%5C%5C%5C+%26%5Ctext%7Bunsigned%7D%5C+%5C+B%3D4294967295%5C%5C+%26B%2B1%3D0%5C%5C%5C%5C+%26%5Ctext%7Bdouble%7D%5C+%5C+C%3D2%5E%7B1023%7D%5Ctimes%282-2%5E%7B52%7D%29%5C%5C+%26C%2B2%5E%7B-%5Cinfty%7D%3D%2B%5Cinfty%5C%5C+%26%28-%5Cinfty+%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E7%BB%9D%E5%AF%B9%E5%80%BC%E8%B6%85%E7%BA%A7%E5%A4%A7%E7%9A%84%E8%B4%9F%E6%95%B0%2C+%E4%B8%8D%E4%BB%A3%E8%A1%A8%E6%95%B0%E5%AD%A6%E4%B8%8A%E7%9A%84%E8%B4%9F%E6%97%A0%E7%A9%B7%29%5C%5C%5C%5C+%26%5Ctext%7Bdouble%7D%5C+%5C+D%3D2%5E%7B-1022%7D%5C%5C+%26D-2%5E%7B-%5Cinfty%7D%3D%2B0%5C%5C+%26%28-%5Cinfty+%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E7%BB%9D%E5%AF%B9%E5%80%BC%E8%B6%85%E7%BA%A7%E5%A4%A7%E7%9A%84%E8%B4%9F%E6%95%B0%2C+%E4%B8%8D%E4%BB%A3%E8%A1%A8%E6%95%B0%E5%AD%A6%E4%B8%8A%E7%9A%84%E8%B4%9F%E6%97%A0%E7%A9%B7%29%5C%5C%5C%5C+%26%5Ctext%7Bdouble%7D%5C+%5C+E%3D0%5C%5C+%26E%3D%2B0%5C%5C%5C%5C+%26%5Ctext%7Blong+long+unsigned+int%7D%5C+%5C+F%3D18446744073709551615%5C%5C+%26F%2B1%3D0%5C%5C%5C%5C+%26%5Ctext%7Blong+long+unsigned+int%7D%5C+%5C+F%3D1%5Ctext%7BULL%7D%5C%5C+%26F%3C%3C63%3DF%5Ctimes2%5E%7B63%7D%3D9223372036854775808%5C%5C%5C%5C+%26%5Ctext%7Blong+long+unsigned+int%7D%5C+%5C+F%3D1%5Ctext%7BULL%7D%5C%5C+%26F%3C%3C64%3DF%5Ctimes2%5E%7B64%7D%3D1%5C%5C%5C%5C+%26%5Ctext%7Blong+long+unsigned+int%7D%5C+%5C+F%3D1%5Ctext%7BULL%7D%5C%5C+%26F%3C%3C65%3DF%5Ctimes2%5E%7B65%7D%3D2%5C%5C%5C%5C+%26%5Ctext%7Blong+long+unsigned+int%7D%5C+%5C+F%3D1%5Ctext%7BULL%7D%5C%5C+%26F%3C%3C1048575%3DF%5Ctimes2%5E%7B1048575%7D%3D9223372036854775808%5C%5C%5C%5C+%26%5Ctext%7Bint%7D%5C+%5C+G%3D123456789%5C%5C+%26%5Ctext%7Bint%7D%5C+%5C+H%3D123456789%5C%5C+%26GH%3D%28123456789%29%5E2%3D-1757895751%5C%5C%5C%5C+%5Cend%7Balign%7D" alt="\begin{align} &\text{int}\ \ A=2147483647\\ &A+1=-2147483648\\\\ &\text{unsigned}\ \ B=4294967295\\ &B+1=0\\\\ &\text{double}\ \ C=2^{1023}\times(2-2^{52})\\ &C+2^{-\infty}=+\infty\\ &(-\infty 表示一个绝对值超级大的负数, 不代表数学上的负无穷)\\\\ &\text{double}\ \ D=2^{-1022}\\ &D-2^{-\infty}=+0\\ &(-\infty 表示一个绝对值超级大的负数, 不代表数学上的负无穷)\\\\ &\text{double}\ \ E=0\\ &E=+0\\\\ &\text{long long unsigned int}\ \ F=18446744073709551615\\ &F+1=0\\\\ &\text{long long unsigned int}\ \ F=1\text{ULL}\\ &F<<63=F\times2^{63}=9223372036854775808\\\\ &\text{long long unsigned int}\ \ F=1\text{ULL}\\ &F<<64=F\times2^{64}=1\\\\ &\text{long long unsigned int}\ \ F=1\text{ULL}\\ &F<<65=F\times2^{65}=2\\\\ &\text{long long unsigned int}\ \ F=1\text{ULL}\\ &F<
Pandora Eartha:【数据结构】链表的算法和代码实现(C语言)Pandora Eartha:C语言计算100亿质数表
// www.zhihu.com-question-570208543
// Created by Pandora on 2022/12/5.
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#define pi 3.1415926535
double sinTaylor(double x){
bool negative=false;
if(x<0){
negative=true;
x=-x;
}
if(x>2*pi){
int adjust=x/pi/2;
x=x-adjust*2*pi;
}
if(x>pi){
x=2*pi-x;
negative=!negative;
}
if(x>pi/2){
x=pi-x;
}
int sign=1;
unsigned n=0;
double sum=0;
double term=x;
while(fabs(term)>=1e-6){
sum+=sign*term;
n++;
sign=-sign;
term=term*x*x/(2*n+1)/(2*n);
}
if(negative){
sum=-sum;
}
return sum;
}
int main(int argc, const char * argv[]) {
double x=-50000;
printf("%lf\n",sinTaylor(x));
}