arcsin根号下a+x分之x怎么化为x=1-sin平方t分之asin平方t?

在编程中我们总要进行一些数学运算以及数字处理,尤其是浮点数的运算和处理,这篇文章主要介绍C语言下的数学库。而其他语言中的数学库函数的定义以及最终实现也是通过对C数学库的调用来完成的,其内容大同小异,因此就不在这里介绍了。

简单来说浮点数的存储由:S(sign)符号位、E(exponent)指数位、M(mantissa 或significand)尾数位三个部分组成。我们以一个32位的float类型举例来说,一个浮点数N的从高位到低位的存储结构如下:

也就是一个32位的浮点数由1个符号位,8个指数位,23个尾数位组成。 而为了表示不同类型的浮点数,根据存储格式对浮点数进行了如下分类:如果一个浮点数中指数位部分全为1,而尾数位部分全为0则这个浮点数表示为无穷大INFINITY,如果符号位为0表示正无穷大,否则就是负无穷大。

如果一个浮点数中指数位部分全为1,而尾数位部分不全为0则这个浮点数表示为非法数字NAN。因此可以看出非法数字并非一个数字而是一类数字。在下面介绍nan函数时我会更加深入的介绍NAN

如果一个浮点数中除符号位外全部都是0,那么这个浮点数就是0

如果一个浮点数中指数位部分全为0,而尾数位部分不全为0则这个浮点数称为非规格化浮点数,英文称为:subnormal number 或 denormal number 或 denormalized number。非规格化浮点数常用来表示一个非常接近于0的浮点数。

如果一个浮点数中的指数位部分即非全1又非全0。那么这个浮点数称之为规格化浮点数,英文称之为:normal number。我们上面定义的FLT_MIN, DBL_MIN 指的就是最小的规格化浮点数。

我们把规格化浮点数和非规格化浮点数合称为可表示的浮点数,英文称之为:machine representable number

一个规格化浮点数N的值可以用如下公式算出:

从上面的公式中可以看出对于一个32位浮点数来说,指数位占8位,最小值是1(全0为非常规浮点),而最大值是254(全1为无穷或者非法浮点),而减去127则表示指数部分的最小值为-126,最大值为127;同时我们发现除了23位尾数外,还有一个隐藏的1作为尾数的头部。因此我们就很容易得出:FLT_MIN = 1.0 * 2^-126 = 1.e-38FLT_MAX =

一个非规格化浮点数N的值的可以用如下公式算出:

从上面的公式中可以看出对于一个32位的浮点数来说,我们发现虽然非规格化浮点的指数位部分全0,但是这里并不是0-127,而是1-127,同时发现尾数位部分并没有使用隐藏的1作为尾数的头部,而是将头部的1移到了指数部分,这样做的目的是为了保持浮点数字的连续性。我们可以看出当一个浮点数小于FLT_MIN时,他就变为了一个非规格化浮点。我们知道FLT_MIN的值是1.0 * 2^-126。如果非规格化浮点数以-127作为指数,而继续使用1作为尾数的头部时,那么这种数字连续性将会被打破。这也是为什么要定义规格化浮点数和非规格化浮点数的意义所在。可以看出浮点数的这种存储设计的精妙之处!!。

从上面两种类型的浮点数中可以总结出浮点数的计算公式可以表示为:N = 符号 * 尾数 * 2^指数

数字判断函数或宏//如果x是正无穷大返回1,负无穷大返回-1,否则返回0int isinf(x)

FP_NAN:x是一个非法数字

????/2;这个函数提供的另外一个意义在于tan函数的值其实就是对边除以邻边的结果,因此当知道对边和邻边时就可以直接用这个逆三角函数来求得对应的弧度值。假如特殊情况下对边和邻边的值都是0.0,那么如果你调用atan(0.0/0.0)得到的值将是NAN而不是0。因为0.0/0.0的值是NAN,而对NAN调用atan函数返回的也是NAN,但是对atan2(0.0,0.0)调用返回的结果就是正确值0。

从上面的例子中发现当用exp函数时出现了有效数字损失而expm1则没有。出现这种问题的原因就是浮点加减运算本身机制的问题,在浮点运算中下面两种类型的运算都有可能出现损失有效数字的情况:两个相近的数相减

两个数量级相差很大的数字相加减

从上面的例子中可以看出当浮点数相近或者差异很大时加减运算出现了有效数字损失的情况,同时上面的例子也给出了一个减少这种损失的简易解决方案。再回到上面exp函数的场景中,因为exp(1.0e-13)的值和1.0是非常接近,因此当对这两个数做减法时就会出现有效数字损失的情况。我们再来考察expm1函数,这个函数主要用于当x接近于0时的场景。我们知道函数 y = e^x - 1 当x趋近于0时的极限是0,因此我们可以用泰勒级数来展开他:

既然上面已经存在了一个exp函数,如果我们要实现相同的功能按理来只要:x*exp(n)就好了,为什么还要单独提供一个新的ldexp函数呢?原因就是ldexp函数其实是一个用来构造浮点数的函数,我们知道浮点数的格式定义在符号*尾数*2^指数,刚好和ldexp所实现的功能是一致的,这里的x用来指定符号*尾数,而n则指定为指数。因此我们就可以借助这个函数来实现浮点数的构造。

这里的FLT_RADIX是浮点数存储里面的基数(在float.h中有定义这个宏),一般情况下是2,这时候这个函数就和ldexp函数是一致的。但是有些系统的浮点数存储并不是以2为基数(比如IBM 360的机器)。因此如果你要构造一个和机器相关的浮点数时就用这个函数。

这个函数的使用场景主要用于当x趋近于0的情况,上面曾经描述过当两个浮点数之间的数量值相差很大时数字的加减会存在有效位丢失的情况。因此如果我们用log函数来计算时当x趋近于0的ln(x+1)时就会存在有效位的损失情况。比如下面的例子:double o1 = log(1.0e-13 + 1);

可以看出函数log1p主要用于当x接近于0时的场景。我们知道函数 y = ln(x+1) 当x趋近于0时的极限是0,因此我们可以用泰勒级数来展开他:

可以看出这个级数收敛的很快,因此可以肯定的是log1p函数的内部实现就是通过上面的泰勒级数的方法来实现求值的。

函数返回的是一个小于等于真实指数的最大整数,也就是对返回的值进行了floor操作,具体floor函数的定义见下面。这里的FLT_RADIX是浮点数的基数,大部分系统定义为2。下面是这个函数的一些例子:logb(2.5) == floor(log2(2.5)) == 1;

函数返回的是一个小于等于真实指数的最大整数,也就是对返回的值进行了floor操作,具体floor函数的定义见下面。需要注意的是这里返回的类型是整型,因此不可能存在返回NAN或者INFINITY的情况。下面是当x是0或者负数时返回的特殊值:FP_ILOGB0:  当x是0时返回这个特殊值。

FP_ILOGBNAN:当x是负数时返回这个特殊值。

log2,logb返回的都是浮点型,因此有可能返回INFINITY和NAN这两个特殊值;而ilogb则返回的是整型,因此如果x是特殊的话那么将会返回FP_ILOGB0和FP_ILOGBNAN两个值。

log2返回的是有可能带小数的指数,而logb和ilogb则返回的是一个不大于实际指数的整数。

这个函数可以用来求直角三角形的斜边长度。

误差函数主要用于概率论和偏微分方程中使用,具体参考误差函数

伽玛函数其实就是阶乘在实数上的扩展,一般我们知道3! = 3*2*1 = 8。那么我们要求2.5!怎么办,这时候就可以用这个函数来实现。这个函数也可以用来进行阶乘计算。 注意这里是x-1后再计算的。

举例来说我们要对于一个负浮点数按0.5进行四舍五入处理:即当某个负数的小数部分大于等于0并且小于0.5时则舍弃掉小数部分,而当小数部分大于等于0.5并且小于1时则等于0.5。我们就可以用ceil函数来实现如下:double y = ceil(x*0.5)/0.5;

举例来说我们要对于一个正浮点数按0.5进行四舍五入处理:即当某个正数的小数部分大于等于0并且小于0.5时则舍弃掉小数部分,而当小数部分大于等于0.5并且小于1时则等于0.5。我们就可以用floor函数来实现如下:double y = floor(x*0.5)/0.5;

//下面三个函数返回的是整数。

//下面三个函数是C99或者gnu99中的函数。

//下面三个函数是C99或者gnu99中的函数。

如果x是正数,那么当小数部分小于0.5则返回的整数小于浮点数,如果小数部分大于等于0.5则返回的整数大于浮点数;如果x是负数,那么当小数部分小于0.5则返回的整数大于浮点数,如果小数部分大于等于0.5则返回的整数小于浮点数。

这个函数和floor函数的区别主要体现在负数上,对一个负数求floor则会返回一个小于等于负数的负整数,而对一个负数求trunc则会返回一个大于等于负数的负整数。

函数返回值r = x - n*y, 其中n等于x/y的值截取的整数。

1。从上面的描述可以看出fmod和remainder的区别主要在于x/y的整数部分的处理不一样:前者是取x/y的整数来算余数,而后者则取最接近x/y的整数来算余数。

这个函数和remainder函数一样,只不过会将整数商也返回给quo,也就是说r = x - n *y这个等式中,r作为函数的返回,而n则返回给quo。

函数返回小数部分,整数部分存储在p中。这里面返回值和p都和x具有相同的符号。

函数返回尾数*符号部分,指数部分存储在p中。需要明确的是如果浮点数x为0或者非规格化浮点数时按浮点数的定义格式返回尾数和指数,而当x为规格化浮点数那么返回的值的区间是[0.5, 1)。这里的返回值和指数值p和上面介绍的规格化浮点数格式:符号 * (1.尾数) * 2^指数有差异。因为按照定义返回的尾数部分应该是1.xxx,但是这里的返回值却是[0.5,

这个函数和上面的ldexp函数为互逆函数。要详细的了解浮点数存储格式请参考

这个函数的作用是实现符号的赋值,有就是将y的符号赋值给x。

前面我有介绍了浮点数里面有两个特殊的值:无穷INFINITY和非法NAN,既然这两个数字都可以用浮点数来描述,那么他就肯定也有对应的存储格式。我们知道浮点数的格式为:符号*尾数*2^指数。在IEEE754标准中就对无穷和非法这两种特殊的数进行了定义:当浮点数中的指数部分的二进制位全为1。而尾数部分的二进制位全为0时则表示的浮点数是无穷INFINITY,如果符号位为0则表示正无穷大,而符号位为1则表示负无穷大。

当浮点数中的指数部分的二进制位全为1。而尾数部分的二进制位不全为0时则表示的浮点数是非法数字NAN,或者表示为未定义的数字。

从上面的对NAN的定义可以得出非法数字并不是一个具体的数字而是一类数字,因此对两个为NAN的浮点数字并不能用等号来比较。以32位IEEE单精度浮点数的NAN为例,按位表示即:S111 1111 1AXX XXXX XXXX XXXX XXXX XXXX,其中的S是符号位,而符号位后面的指数位为8个1表示这个数字是一个特殊的浮点数,剩余的A和X则组成为了尾数部分,因为是NAN 所以我们要求A和X这些位中至少有一个是1。在IEEE 754-2008标准中,又对NAN的类型进行了细分:如果A = 1,则该数是quiet NAN。也就是quiet NAN中尾数的最高位为1。

区分两种NAN的目的是为了更好的对浮点数进行处理。一般我们将signaling NAN来表示为某个数字未初始化,而将quiet NAN则用来表示浮点运算的结果出现了某类异常,比如0除异常,比如负数开根异常等等。既然quiet NAN可以用来对无效数字进行分类,也就是说我们可以构建出一个有类别标志的quiet NAN。因此nan函数就是一个专门构建具有无效类别的NAN函数(绕了这么多终于说到点子上了)。nan函数中的tagp参数就是用来指定非法数字中的类别,虽然参数类型是字符串,但是要求里面的值必须是整数或者空字符串,而且系统在构造一个quiet

具体操作时我们可以用如下来方法来处理各种异常情况://定义部分:float  testfn(){

//有异常时根据不同的情况返回不同的nan。

如果x等于y则返回x。这个函数主要用来实现那些需要高精度增量循环的处理逻辑。也就是说如果对浮点数进行for循环处理时,这个函数可以用来实现最小的浮点数可表示的数字的增量。比如下面的代码:for (double x = 0.1; x 

注意这里是下一个可表示的浮点数,也就是说当x为0而y为1时,那么返回的值将是最小的非常规浮点数;而如果x为1而y为2时,那么返回的值将是1+DBL_MIN(or FLT_MIN). 下面是具体的示例代码:// 0.0f == 0b

这个函数返回x*y+z的结果,而且会保证中间计算不会丢失精度。这个函数会比直接用x*y+z要快,因为CPU中专门提供了一个用于浮点数乘加的指令FMA。具体情况请参考关于浮点乘加器方面的资料和应用。

最后欢迎大家访问我的github站点 多多点赞,多多支持!

我要回帖

更多关于 arcsin(a+b)展开 的文章

 

随机推荐