⭐️ 关键字深度剖析 ⭐️第五章(深入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自定义


相关文章
|
存储 数据可视化 编译器
【C语言】union 关键字详解
联合体(`union`)是一种强大的数据结构,在C语言中具有广泛的应用。通过共享内存位置,联合体可以在不同时间存储不同类型的数据,从而节省内存。在嵌入式系统、硬件编程和协议解析等领域,联合体的使用尤为常见。理解和正确使用联合体可以使代码更加高效和灵活,特别是在内存受限的系统中。
795 3
【C语言】union 关键字详解
|
C语言
【C语言】break 关键字详解
- `break` 关键字用于提前退出循环体或 `switch` 语句的执行。 - 在 `for`、`while` 和 `do-while` 循环中,`break` 可以帮助程序在满足特定条件时退出循环。 - 在 `switch` 语句中,`break` 用于终止 `case` 代码块的执行,避免代码“穿透”到下一个 `case`。 - 注意 `break` 只会退出最内层的循环或 `switch` 语句,确保在嵌套结构中正确使用 `break` 以避免意外的控制流行为。
1334 2
|
传感器 安全 编译器
【C语言】enum 关键字详解
`enum`关键字在C语言中提供了一种简洁而高效的方法来定义一组相关的常量。通过使用枚举,可以提高代码的可读性、可维护性,并减少错误的发生。在实际应用中,枚举广泛用于表示状态、命令、错误码等,为开发者提供了更清晰的代码结构和更方便的调试手段。通过合理使用枚举,可以编写出更高质量、更易维护的C语言程序。
800 2
|
缓存 安全 编译器
【C语言】volatile 关键字详解
`volatile` 关键字在 C 语言中用于防止编译器对某些变量进行优化,确保每次访问该变量时都直接从内存中读取最新的值。它主要用于处理硬件寄存器和多线程中的共享变量。然而,`volatile` 不保证操作的原子性和顺序,因此在多线程环境中,仍然需要适当的同步机制来确保线程安全。
754 2
|
存储 编译器 程序员
【C语言】auto 关键字详解
`auto` 关键字用于声明局部变量的自动存储类,其作用主要体现在变量的生命周期上。尽管现代C语言中 `auto` 的使用较少,理解其历史背景和作用对于掌握C语言的存储类及变量管理仍然很重要。局部变量默认即为 `auto` 类型,因此在实际编程中,通常不需要显式声明 `auto`。了解 `auto` 关键字有助于更好地理解C语言的存储类及其在不同场景中的应用。
662 1
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
454 7
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
11月前
|
存储 人工智能 Java
一文轻松拿捏C语言的指针的基础使用
本文介绍了C语言中的指针概念,包括直接访问和间接访问内存的方式、指针变量的定义与使用、取址运算符`&`和取值运算符`*`的应用,帮助读者深入理解指针这一C语言的核心概念。君志所向,一往无前!
243 0
|
C语言
【C语言】continue 关键字详解
`continue` 关键字在 C 语言中用于跳过当前循环中的剩余代码,并立即开始下一次迭代。它主要用于控制循环中的流程,使程序在满足特定条件时跳过某些代码。
1364 1
【C语言】continue 关键字详解
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
1450 9
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
431 7