⭐️ 关键字深度剖析 ⭐️第五章(深入C语言三种类型(float/bool/指针)与“零值“的比较)

简介: 浮点数在内存中存储,并不想我们想的是完整存储的在十进制转化成为二进制,是有可能有精度损失的

float类型与"零值"的比较


浮点数的存储

浮点数在内存中存储,并不想我们想的是完整存储的

在十进制转化成为二进制,是有可能有精度损失的

注意

这里的损失,不是一味的减少了,还有可能增多

浮点数本身存储的时候,在计算不尽的时候,会四舍五入或者其他策略


int main()
{
double x = 3.6;
printf("%.50f\n", x);
system("pause");
return 0;
}


20210801162522429.png

int main() 
{ 
 double x = 1.0;
 double y = 0.1;
 printf("%.50f\n", x - 0.9);
 printf("%.50f\n", y);
 if ((x - 0.9) == y)
{
 printf("you can see me!\n");
 }
else
{
printf("oops\n");
 }
system("pause");
 return 0;
 }

20210801162807645.png

解决方案:进行范围精度比较

//伪代码 
if((x-y) > -精度 && (x-y) < 精度)
{
 //TODO
}
//伪代码-简洁版 
if(fabs(x-y) < 精度)
{//fabs是浮点数求绝对值
//TODO
}

精度

自己设置?后面如果有需要,可以试试,通常是宏定义

使用系统精度?暂时推荐

20210801164327341.png

#include<float.h> //使用下面两个精度,需要包含该头文件 
DBL_EPSILON //double 最小精度 
FLT_EPSILON //float 最小精度 
//代码调整后 
#include <stdio.h> 
#include <math.h> //必须包含math.h,要不然无法使用fabs 
#include <float.h> //必须包含,要不然无法使用系统精度 
#include <windows.h> 
int main() 
{ 
 double x = 1.0;
 double y = 0.1;
 printf("%.50f\n", x - 0.9);
 printf("%.50f\n", y);
 if (fabs((x - 0.9) - y) < DBL_EPSILON)
{ //原始数据是浮点数,我们就用DBL_EPSILON 
 printf("you can see me!\n");
}
 else
{
 printf("oops\n");
}
 system("pause");
 return 0; }

定义

//两个精度定义 
#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */ 
#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */

XXX_EPSILON 是最小误差 , 是: XXX_EPSILON + n 不等于 n 的最小的正数。

EPSILON 这个单词翻译过来是 'ε' 的意思,数学上,就是极小的正数 ---- 来自百度  


//最终代码 
#include <stdio.h> 
#include <math.h> 
#include <float.h> 
#include <windows.h> 
int main() 
{
 double x = 0.00000000000000000000001;
 //if (fabs(x-0.0) < DBL_EPSILON){ //写法1 
//if (fabs(x) < DBL_EPSILON){ //写法2 
if(x > -DBL_EPSILON && x < DBL_EPSILON)
{ //书中写法
 printf("you can see me!\n");
 }
else
{
 printf("oops\n");
}
 system("pause");
 return 0; }

关于需不需要取等号

x > -DBL_EPSILON && x < DBL_EPSILON: 为何不是>= && <= 呢?

个人看法:XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数

XXX_EPSILON+n不等于n的最小的正数:

有很多数字+n都可以不等于n,但是XXX_EPSILON是最小的

but,XXX_EPSILON依旧是引起不等的一员

XXX_EPSILON+n不等于n的最小的正数:

有很多数字+n都可以不等于n,但是XXX_EPSILON是最小的

but,XXX_EPSILON依旧是引起不等的一员

Bool(布尔)类型与"零值"的比较


深入理解C 中 bool

C语言有没有bool类型?

c99之前,主要是c90/c89是没有的

目前大部分书,都是认为没有的

因为书,一般都要落后于行业

但是c99引入了_Bool类型

你没有看错,_Bool就是一个类型

不过在新增头文件stdbool.h中,被重新用宏写成了 bool,为了保证C/C++兼容性

//测试代码1 
#include <stdio.h> 
#include <stdbool.h> //没有这个头文件会报错,使用新特性一定要加上 
#include <windows.h> 
int main()
{ bool ret = false;
 ret = true;
 printf("%d\n", sizeof(ret)); //vs2013 和 Linux中都是1 
system("pause");
 return 0;
 }


//查看源码 
/* stdbool.h standard header */ 
//stdbool.h #ifndef _STDBOOL 
#define _STDBOOL 
#define __bool_true_false_are_defined 1 
#ifndef __cplusplus 
#define bool _Bool //c99中是一个关键字哦,后续可以使用bool
#define false 0 //假 
#define true 1 //真

理论上,表示真假,需要一个bit就够了

不过这个问题,还是要取决于编译器的理解

vs2013中认为是1个字节


but

int main() 
{ //在vs中,光标选中BOOL,单击右键,可以看到转到定义,就能看到BOOL是什么 
 BOOL ret = FALSE;
 ret = TRUE;
 printf("%d\n", sizeof(ret)); //输出结果是4,因为在源代码中,是这么定义的:typedef int BOOL; system("pause");
 return 0;
 }

这是Microsoft自己搞的一套BOOL值。在vs中转到BOOL对应的头文件,翻到最上面,就能看到微软的版权信息。可以通过编译,但可移植性差。


总结:

1. 优先使用c90,就是我们之前以及后面一直用的方式

2. 万一非得使用bool,推荐c99标准,不推荐MS自定义


相关文章
|
24天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
45 0
|
23天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
15 2
|
24天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
24天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
30天前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
30天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
23天前
|
编译器 C语言
【c语言】指针就该这么学(2)
本文详细介绍了指针与数组的关系,包括指针访问数组、一维数组传参、二级指针、指针数组和数组指针等内容。通过具体代码示例,解释了数组名作为首元素地址的用法,以及如何使用指针数组模拟二维数组和传递二维数组。文章还强调了数组指针与指针数组的区别,并通过调试窗口展示了不同类型指针的差异。最后,总结了指针在数组操作中的重要性和应用场景。
17 0
|
6月前
|
存储 Java
百度搜索:蓝易云【Java语言之float、double内存存储方式】
由于使用IEEE 754标准进行存储,float和double类型可以表示非常大或非常小的浮点数,并且具有一定的精度。然而,由于浮点数的特性,它们在进行精确计算时可能会存在舍入误差。在编写Java程序时,需要注意使
97 0
|
30天前
|
存储 C语言
使用 sizeof 操作符计算int, float, double 和 char四种变量字节大小
【10月更文挑战第13天】使用 sizeof 操作符计算int, float, double 和 char四种变量字节大小。
76 1
|
4月前
|
存储 编译器 C++
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么