首页 > 其他分享 >double型最大正值和最小正值探秘

double型最大正值和最小正值探秘

时间:2024-03-13 18:01:40浏览次数:22  
标签:输出 int double 最小 数值 324 正值 探秘

【题目来源】

刘汝佳《算法竞赛入门经典  第2版》第一章习题——问题3:double型浮点数最大正数值和最小正数值分别是多少(不必特别精确)?

书中并未给出标准答案,这道题应该怎么解呢?老金还着实费了不少脑细胞。

一、跑到海枯石烂的代码

网上查到这样的代码:

#include <stdio.h>
int main(){
    double i=0.0000000000000001;
    for(;i>0;i+=0.0000000000000001){
    }
    printf("%.100lf\n%.100lf\n",i,i-1);
    return 0;
}

实际测试了一下,运行到海枯石烂也没等到结果。如果有人等到结果还望告知。

从代码看,其逻辑应该是数值超限时数值的符号会变号,由正数变成负数。

鉴于有这么虐人的运行时间,估计出题者的标准答案肯定不是如此。

二、利用头文件宏获取

在float.h头文件中,定义了两个宏:

DBL_MAX:double类型能够表示的最大有限正数。

DBL_MIN:double类型能够表示的最小正规化正数值(可以理解为比最小正数大,但接近于最小正数的值)。

#include <stdio.h>
#include <float.h>
int main() {
    printf("最大正数值: %g\n", DBL_MAX);
    printf("最小正规化正数值: %g\n", DBL_MIN);
    return 0;
}

结果输出:

最大正数值: 1.79769e+308

最小正规化正数值: 2.22507e-308

这应该是比较靠谱的数据了,这个值真的是很大很大,所以在实际编程时,完全没有必要考虑数值超限的问题。

因此,浮点数的主要问题是误差,而不是数值超限。

三、老金的半自动步枪

老金经过尝试,可以用一种“编程+人工确认”的半自动输出方法。虽然是半自动方法,但是非常简单高效。

因为要求最大正数和最小正数,数字肯定会非常大,所以要用到科学记数法表示。科学记数法表示的数分为基数部分和指数部分,只要分别确定这两部分,这个数也就确定了。

1. 求最大正数值

 (1) 求最大正数值的指数部分

思路是将基数设为1,再将指数从0进行累加,然后人工确认输出结果出现异常的地方,就是指数的最大值。

#include<stdio.h>
int main(){
    //求最大正数值的指数部分
    double max=1e0;
    for(int i=1;i<=400;i++){
        max*=1e1;
        printf("%d %e\n",i, max);
    }
    return 0;
}

代码中的循环条件“i<=400”根据实际测试结果给的,这时输出已经出现异常。

根据下图输出结果,可知最大指数为308。

上面的“1.#INF00e+000”是什么东东呢?这其实也是一种科学记数法的表示形式,只不过指部为0,而基数的前半部分“1.#INF”表示“无穷大inf (infinity 的缩写)”,所以“1.#INF00e+000”自然也表示无穷大。但这只是对“无穷大”的数的一种标记方式,它本身并不是一个具体的值,也就不能和其他的值作比较,所以这里很难通过程序实现自动判断数值超限位置。

(2) 求最大正数值的基数部分

上面已经求出最大指数是308,下面就将指数设为308,再将基数从1进行累加,然后人工确认输出结果出现异常的地方,就是基数的最大值。

#include<stdio.h>
int main(){
    //求最大正数值的基数部分
    double max=1e308;
    for(int i=1;i<=1000;i++){
        max+=0.01e308;
        printf("%d %e\n",i, max);
    }
    return 0;
}

根据下图输出结果,可知最大基数为1.79,所以double型浮点数最大正数值为1.79e+308,与前面用宏给出的最大值1.79769e+308一致(只不过咱们的精度没有它那么高)。

2. 求最小正数值

(1) 求最小正数值的指数部分

思路是将基数设为1,再将指数从0进行累减,然后人工确认输出结果出现异常的地方,就是指数的最小值。

#include<stdio.h>
int main(){
    //求最小正数值的指数
    double min=1e0;
    for(int i=1;i<=400;i++){
        min*=1e-1;
        printf("%d %e\n",i, min);
    }
    return 0;
}

根据下图输出结果,可知最小指数为-324

(2) 求最小正数值的基数部分

上面已经求出最小指数是324,下面就将指数设为324,再将基数从9进行累减,然后人工确认输出结果出现异常的地方,就是基数的最小值。

但是这时候已经不能靠代码进行累减了,因为9e-324本来已经小到接近极限了,没法再让程序减去一个固定的最小值了,所以此时就要人工实现累减。方法也很简单,就是将下面代码中的基数9依次改为8、7、6、5、4、3、2、1后逐一运行程序。

#include<stdio.h>
int main(){
    //求最小正数值的基数
    double min=9e-324;
    printf("%e\n", min);
    return 0;
}

输出结果如下:

9e-324输出9.881313e-324

8e-324输出9.881313e-324

7e-324输出4.940656e-324

6e-324输出4.940656e-324

5e-324输出4.940656e-324

4e-324输出4.940656e-324

3e-324输出4.940656e-324

2e-324输出0.000000e+000

1e-324输出0.000000e+000

可见,当改为7e-324以下、3e-324以上时,程序一律将值视为4.940656e-324,当改到2e-324时程序已经将它视为0。

所以double型浮点数最小正数值为4.940656e-324,前面由宏输出的结果为2.22507e-308,咱们得到的值比它这个值还要小很多。

综上,老金这种半自动化的方法虽然不那么先进,但却是三种方法中最简单高效、最接近标准答案的。

标签:输出,int,double,最小,数值,324,正值,探秘
From: https://blog.csdn.net/jjmhx/article/details/136686264

相关文章

  • Elasticsearch探秘:原理剖析、高级运用与实战经验【文末送书-37】
    文章目录Elasticsearch探秘:原理剖析、高级运用与实战经验进阶使用方法数据建模与映射实战工程案例索引阻塞的种类什么时候使用阻塞?一本书讲透Elasticsearch:原理、进阶与工程实践【文末送书-37】Elasticsearch探秘:原理剖析、高级运用与实战经验Elasticsearch作为一个......
  • 动手学强化学习(八.2):double-DQN
    一、代码importrandomimportgymimportnumpyasnpimporttorchimporttorch.nn.functionalasFimportmatplotlib.pyplotaspltimportrl_utilsfromtqdmimporttqdmclassQnet(torch.nn.Module):'''只有一层隐藏层的Q网络'''de......
  • 程序员搞副业经验分享:卖书、做网课,探秘前同事的经验之谈
    为了更深入了解程序员如何进行创收,今天与一位曾在几年前成功通过卖书和网课获取收益的前同事进行了交流。由于他曾有过丰富的经验,我向他请教了一些相关经验,以下是我想获取的信息:你目前还在通过做网课获得收益吗?没有。不再从事网课的主要原因有两点:首先,工作非常繁忙,每天都在996(周......
  • doubletrouble 双重麻烦
    doubletrouble双重麻烦一信息收集IP扫描端口扫描80目录扫描访问uploads访问secret发现图片下载图片安装工具谷歌网址https://github.com/RickdeJager/stegseek/releases解压字典解析图片查看output得到邮箱和密码登录80网页......
  • vulnhub靶机:doubletrouble
    一:信息收集1:主机发现2:端口扫描3:敏感目录探测二:渗透测试1:敏感目录扫到三个需要重点关注http://10.4.7.140/core发现该目录下存在很多敏感文件,其中有一个文件下有邮箱用户名和密码,应该是mysql数据库的用户名和密码http://10.4.7.140/uploads猜测该目录应该是登陆后上传......
  • WPF 非Control元素模拟鼠标双击MouseDoubleClick事件
    privatereadonlyDispatcherTimer_mouseLeftTimer=newDispatcherTimer();privatereadonlyDispatcherTimer_mouseRightTimer=newDispatcherTimer();publicClass(){_mouseLeftTimer.Interval=TimeSpan.FromMilliseconds(MOUSE_CLICK_DE......
  • 函数探秘:深入理解C语言函数,实现高效模块化编程
    ✨✨欢迎大家来到贝蒂大讲堂✨✨......
  • C# 的显示转换 *.Parse(string) Convert.ToInt32(double value)
    //显式转换(类型)///(int)表示使用强制的显示转换,是一种类型转换,C#默认的整形是int32,///因此使用此方法转成int32不遵循四舍五入,直截取整数部分///(int)5.12结果是5///Int.Parse()指把string类型转换int......
  • C# 的浮点类型 float double 和十进制类型 decimal
    //浮点型数据floatdouble(双精度)//floatf=1.1;//ps:写小数的时候只要后面没有加上f/F默认是double类型//正确的定义doubled=1.1;floatf=1.1F;floatf1=1f;//f=d;//ps......
  • C++动态内存分配探秘:new与malloc的关键差异及实例解析
     概述:在C++中,new和malloc均用于动态内存分配,但存在关键差异。new是C++运算符,能调用构造函数,返回类型明确;而malloc是C函数,仅分配内存,需手动类型转换。示例源代码生动演示了它们在构造函数调用和类型信息方面的不同。在C++中,new 和 malloc 都用于动态内存分配,但它们之间......