c语言中浮点数怎么判断是否合法(深入理解浮点数在值域范围内表示大整数的舍掉和舍入位的问题)

 2024-09-16  阅读 532  评论 0

摘要:看以下实例:// 有问题的版本 #include int main() {Float sum = 0.0f;for (int i = 0; i < 10000; i ) sum = i 1;printf("Sum of 1~10000: %f\n", sum); pri

看以下实例:

// 有问题的版本 #include <stdio.h> int main() { Float sum = 0.0f; for (int i = 0; i < 10000; i ) sum = i 1; printf("Sum of 1~10000: %f\n", sum); printf("Sum of 1~10000: %f\n",10001*5000.0); getchar(); return 0; } /* output: Sum of 1~10000: 50002896.000000 Sum of 1~10000: 50005000.000000 */

我们知道,float使用1个符号位,8个阶码和23个尾码。

阶码采取移码,E = e 2^(8-1)-1

其值域有:

Float(IEEE754) 32 -3.4028E 38 3.4028E 38

为什么会有这个情况呢?

问题出在尾数只有23位,当其全部用来表示整数时,只能表示32位,也就是2^24-12 = 16777215

当大于这个数字时,就存在丢弃和舍入位的可能。

c语言中浮点数怎么判断是否合法(深入理解浮点数在值域范围内表示大整数的舍掉和舍入位的问题)(1)

看累加到多少开始有精度损失:

#include <stdio.h> #define MM 5793 int main() { float sum = 0.0f; for (int i = 0; i < MM; i ) { sum = i 1; printf("%d %f\n",i,sum); } printf("Sum of 1~%d: %f\n",MM,sum); printf("Sum of 1~%d: %f\n",MM,(MM 1)*MM/2.0); getchar(); return 0; } /* output: …… 5791 16776528.000000 5792 16782321.000000 Sum of 1~5793: 16782320.000000 Sum of 1~5793: 16782321.000000 */

看下面实例的演示:

#include <stdio.h> int main() { float sum =16777215.0f; printf("%f\n",sum); sum; printf("%f\n",sum); sum ; printf("%f\n",sum); sum ; printf("%f\n",sum); sum ; printf("%f\n",sum); sum ; printf("%f\n",sum); sum ; printf("%f\n",sum); getchar(); return 0; } /* 16777215.000000 16777216.000000 16777217.000000 16777217.000000 16777217.000000 16777217.000000 16777217.000000 */

到底是怎样舍掉和舍入的呢?再看下面的实例:

#include <stdio.h> int main() { float sum =16777215; int si = sum; printf("%f\n",sum); // 16777215.000000 sum =16777216; printf("%f\n",sum); // 16777216.000000 sum =16777217; printf("%f\n",sum); // 16777216.000000 // 舍掉1位 sum =16777218; printf("%f\n",sum); // 16777218.000000 sum =16777219; printf("%f\n",sum); // 16777220.000000 // 舍入1位 sum =16777220; printf("%f\n",sum); // 16777220.000000 sum =16777221; printf("%f\n",sum); // 16777220.000000 // 舍掉1位 getchar(); return 0; }

数值增大几倍:

#include <stdio.h> int main() { float sum =97897215; int si = sum; printf("%f\n",sum); sum =97897216; printf("%f\n",sum); sum =97897217; printf("%f\n",sum); sum =97897218; printf("%f\n",sum); sum =97897219; printf("%f\n",sum); sum =97897220; printf("%f\n",sum); sum =97897221; printf("%f\n",sum); sum =97897222; printf("%f\n",sum); getchar(); return 0; } /* output: 97897216.000000 97897216.000000 97897216.000000 97897216.000000 97897216.000000 97897216.000000 97897224.000000 97897224.000000 */

float类型的97897222的阶码和尾码:

c语言中浮点数怎么判断是否合法(深入理解浮点数在值域范围内表示大整数的舍掉和舍入位的问题)(2)

其存在舍入和舍掉位的位数 = 阶码-127-23。

同理,double类型也存在同样的情况,只是其起点更长。

下面这样写参数可能会转换为double,放到了寄存器,则看不到精度丢失。(release编译更会如此)

#include <stdio.h> int main() { float sum =16777215; printf("%f\n",sum); printf("%f\n", sum); printf("%f\n", sum); printf("%f\n", sum); printf("%f\n", sum); getchar(); return 0; } /* 16777215.000000 16777216.000000 16777217.000000 16777218.000000 16777219.000000 */

上面将sum的类型从float改成double就不会存在上述问题。因为double的尾码高达52位。

-End-

,

版权声明:xxxxxxxxx;

原文链接:http://cn.tdroid.net/ce212Cz0EBwgBVFA.html

发表评论:

管理员

  • 内容266037
  • 积分0
  • 金币0
关于我们
lecms主程序为免费提供使用,使用者不得将本系统应用于任何形式的非法用途,由此产生的一切法律风险,需由使用者自行承担,与本站和开发者无关。一旦使用lecms,表示您即承认您已阅读、理解并同意受此条款的约束,并遵守所有相应法律和法规。
联系方式
电话:
地址:广东省中山市
Email:
注册登录
注册帐号
登录帐号

Copyright © 2022 太卓开发网 Inc. 保留所有权利。 泰达科技网易库网

页面耗时0.1020秒, 内存占用1.34 MB, 访问数据库18次