添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

本文章解决的问题是:整形计算赋值给浮点数变量时,浮点变量数值看似异常的问题。问题很基础,适合给同样刚刚开始学习C语言的编程小白参考,且主要作用是希望大家引以为戒,不要犯和作者一样的错误。

在做题目的过程中发现关于double类型的一个问题:

原题目是:由用户输入项数,计算如下两个无穷级数:

原代码如下:

//练习题6.16.12.c -- 无穷级数
#include<stdio.h>
int power1(int n);
int main(void)
	double s1 = 0.0,s2 = 0.0,a = 1.0;
	int i = 0,t;
	long long n;
	printf("s1=1+1/2+1/3+1/4...\n");
	printf("s2=1-1/2+1/3-1/4...\n");
	printf("请输入计算项数,以计算以上两个无穷级数(结束输入q):");
	t = scanf("%LLd",&n);
	while(t == 1)
		for(;i++ < n;a = 1 / (i + 1)) 
			s1 += a;
			s2 += power1(i)*a;
		printf("s1前%LLd项和为:%lf,s2前%d项和为:%lf\n\n",n,s1,n,s2);
		printf("s1=1+1/2+1/3+1/4...\n");
		printf("s2=1-1/2+1/3-1/4...\n");
		printf("请输入计算项数,以计算以上两个无穷级数(结束输入q):");
		t = scanf("%LLd",&n);
		i = 0,s1 = 0.0,s2= 0.0,a = 1.0;
	printf("Done!");
	return 0;
int power1(int n)
	int a = -1;
	while(n-- > 0)
		a = a * (-1);
	return a;

可是无论输入的n值为几,结果都始终为:s1=1,s2=1

 几经查找后,才发现是a的值有问题,又是几经查找后,终于发现原因:整数运算中,/运算会产生"截断"(truncation),简而言之就是暴力舍弃除法结果的小数部分(非四舍五入),截断发生在除法结束的瞬间,无法在整数除法外添加强制类型转换(如(double))进行修正,例:

//测试.c 
#include<stdio.h>
void main(void)
	double a,b,c,d,e;
	a = (double)1 / 2;
	b = 1 / (double)2;
	c = (double)(1 / 2);
	d = 1 / 2;
	e = 1.0/2;
	printf("a=%lf\nb=%lf\nc=%lf\nd=%lf\ne=%lf\n",a,b,c,d,e);

 于是,可以通过如上第1、2、5两种方法,即:对被除数或除数添加强制类型转换,或将除数或被除数之一写为x.0的写法,来进行修正。

而原代码在将1改为1.0后正常运行,debug成功,程序正常运行。

 编程中整数和浮点数的运算规律与日常生活中的计算不尽相同,需要额外注意。

2.10.2 printf输出int值 23 2.10.3 printf输出八进制和十六进制 23 2.10.4 short,long,long long,unsigned int 23 2.10.5 整数溢出 23 2.10.6 大端对齐与小端对齐 23 2.11 CHAR类型 24 2.11.1 char常量,变量 24 2.11.2 printf输出char 24 2.11.3 不可打印char转义符 24 2.11.4 char和unsigned char 25 2.12 点FLOAT,DOUBLE,LONG DOUBLE类型 25 2.12.1 点常量,变量 25 2.12.2 printf输出点数 25 2.13 类型限定 25 2.13.1 const 25 2.13.2 volatile 26 2.13.3 register 26 3 字符串格式化输出和输入 26 3.1 字符串在计算机内部的存储方式 26 3.2 PRINTF函数,PUTCHAR函数 27 3.3 SCANF函数与GETCHAR函数 28 4 运算符表达式和语句 29 4.1 基本运算符 29 4.1.1 = 29 4.1.2 + 29 4.1.3 – 29 4.1.4 * 29 4.1.5 / 29 4.1.6 % 29 4.1.7 += 29 4.1.8 -= 29 4.1.9 *= 29 4.1.10 /= 30 4.1.11 %= 30 4.1.12 ++ 30 4.1.13 -- 30 4.1.14 逗号运算符 30 4.1.15 运算符优先级 30 4.2 复合语句 31 4.3 空语句 31 4.4 类型转化 31 5 条件分支语句 31 5.1 关系运算符 31 5.1.1 < 31 5.1.2 <= 31 5.1.3 > 32 5.1.4 >= 32 5.1.5 == 32 5.1.6 != 32 5.2 关系运算符优先级 32 5.3 逻辑运算符 32 5.3.1 && 32 5.3.2 || 32 5.3.3 ! 33 5.4 IF 33 5.5 IF ELSE 34 5.6 IF ELSE IF 34 5.7 SWITCH与BREAK,DEFAULT 35 5.8 条件运算符? 36 5.9 GOTO语句与标号 36 6 循环语句 36 6.1 WHILE 36 6.2 CONTINUE 37 6.3 BREAK 37 6.4 DO WHILE 37 6.5 FOR 37 6.6 循环嵌套 37 7 数组 38 7.1 一维数组定义与使用 38 7.2 数组在内存的存储方式 38 7.3 一维数组初始化 38 7.4 二维数组定义与使用 39 7.5 二维数组初始化 39 8 字符串与字符数组 39 8.1 字符数组定义 39 8.2 字符数组初始化 39 8.3 字符数组使用 40 8.4 随机数产生函数RAND与SRAND 40 8.5 用SCANF输入字符串 40 8.6 字符串的结束标志 41 8.7 字符串处理函数 41 8.7.1 gets 41 8.7.2 fgets函数 41 8.7.3 puts函数 42 8.7.4 fputs函数 42 8.7.5 strlen,字符串长度 42 8.7.6 strcat,字符串追加 42 8.7.7 strncat,字符串有限追加 43 8.7.8 strcmp,字符串比较 43 8.7.9 strncmp,字符串有限比较 43 8.7.10 strcpy字符串拷贝 43 8.7.11 strncpy字符串有限拷贝 43 8.7.12 sprintf,格式化字符串 43 8.7.13 Sscanf函数 44 8.7.14 strchr查找字符 44 8.7.15 strstr查找子串 44 8.7.16 strtok分割字符串 44 8.7.17 atoi转化为int 45 8.7.18 atof转化为float 45 8.7.19 atol转化为long 45 9 函数 45 9.1 函数的原型和调用 45 9.2 函数的形参与实参 45 9.3 函数的返回类型与返回值 46 9.4 MAIN函数与EXIT函数与函数的RETURN语句 46 9.5 多个源代码文件程序的编译 47 9.5.1 头文件的使用 47 9.5.2 #include与#define的意义 47 9.5.3 #ifndef与#endif 47 9.6 函数的递归 48 9.6.1 递归的过程分析 48 9.6.2 递归的优点 52 9.6.3 递归的缺点 52 1 指针 52 1.1 指针 52 1.1.1 指针的概念 52 1.1.2 指针变量的定义 52 1.1.3 &取地址运算符 52 1.1.4 无类型指针 52 1.1.5 NULL 53 1.1.6 空指针与野指针 53 1.1.7 指针的兼容性 53 1.1.8 指向常量的指针与指针常量 54 1.1.9 指针与数组的关系 54 1.1.10 指针运算 54 1.1.11 通过指针使用数组元素 55 1.1.12 指针数组 55 1.1.13 指向指针的指针(二级指针) 55 1.1.14 指向二维数组的指针 57 1.1.15 指针变量做为函数的参数 57 1.1.16 一维数组名作为函数参数 57 1.1.17 二维数组名作为函数参数 58 1.1.18 const关键字保护数组内容 58 1.1.19 指针做为函数的返回值 58 1.1.20 指向函数的指针 59 1.1.21 把指向函数的指针做为函数的参数 60 1.1.22 memset,memcpy,memmove函数 61 1.1.23 指针小结 63 2 字符指针与字符串 64 2.1 指针和字符串 64 2.2 通过指针访问字符串数组 64 2.3 函数的参数为CHAR * 64 2.4 指针数组做为MAIN函数的形参 65 3 内存管理 65 3.1 作用域 65 3.1.1 auto自动变量 65 3.1.2 register寄存器变量 65 3.1.3 代码块作用域的静态变量 66 3.1.4 代码块作用域外的静态变量 66 3.1.5 全局变量 66 3.1.6 外部变量与extern关键字 66 3.1.7 全局函数和静态函数 66 3.2 内存四区 66 3.2.1 代码区 67 3.2.2 静态区 67 3.2.3 栈区 67 3.2.4 栈溢出 68 3.2.5 堆区 68 3.3 堆的分配和释放 70 3.3.1 malloc 70 3.3.2 free 70 3.3.3 calloc: 70 3.3.4 realloc 71 4 结构体,联合体,枚举与TYPEDEF 71 4.1 结构体 71 4.1.1 定义结构体struct和初始化 71 4.1.2 访问结构体成员 71 4.1.3 结构体的内存对齐模式 72 4.1.4 指定结构体元素的位字段 72 4.1.5 结构数组 72 4.1.6 嵌套结构 73 4.1.7 结构体的赋值 73 4.1.8 指向结构体的指针 73 4.1.9 指向结构体数组的指针 73 4.1.10 结构中的数组成员和指针成员 73 4.1.11 在堆中创建的结构体 74 4.1.12 将结构作为函数参数 74 4.1.13 结构,还是指向结构的指针 74 4.2 联合体 75 4.3 枚举类型 75 4.3.1 枚举定义 75 4.3.2 默认值 76 4.4 TYPEDEF 76 4.5 通过TYPEDEF定义函数指针 76 5 文件操作 77 5.1 FOPEN 77 5.2 二进制和文本模式的区别 77 5.3 FCLOSE 78 5.4 GETC和PUTC函数 78 5.5 EOF与FEOF函数文件结尾 78 5.6 FPRINTF,FSCANF,FGETS,FPUTS函数 78 5.7 STAT函数 78 5.8 FREAD和FWRITE函数 79 5.9 FREAD与FEOF 79 5.10 通过FWRITE将结构保存到二进制文件中 79 5.11 FSEEK函数 80 5.12 FTELL函数 80 5.13 FFLUSH函数 80 5.14 REMOVE函数 81 5.15 RENAME函数 81 6 基础数据结构与算法 82 6.1 什么是数据结构 82 6.2 什么是算法 82 6.3 排序 83 6.3.1 冒泡排序 83 6.3.2 选择排序 83 6.4 查找 83 6.4.1 顺序查找 83 6.4.2 二分查找 83 6.5 链表 84 6.5.1 单向链表定义 84 6.5.2 单向链表数据结构定义 85 6.5.3 单向链表的实现 85 最近一直在用visual effect graph ,常常利用贴图来存储数据,再导入vfx采用SampleTexture结点采样使用,因此涉及到数据的保存等问题;此外这两天才真正算是尝试了computeShader的编写,同时用到了renderTexture存储数据;想来可以做个总结以及留几个还未明白的坑。一、Texture2DTexture2D的创建赋值Setpixel即可,很简单(其他方法请查... 点数的概念点数也称小数或实数。例如,0.0、75.0、4.023、0.27、-937.198 都是合法的小数。这是常见的小数的表现形式,称为十进制形式。C语言中采用float和double关键字来定义小数,float称为单精度点型,double称为双精度点型,long double更长的双精度点型。在任何区间内(如1.0 到 2.0 之间)都存在无穷多个实数,计算机的点数不能表示区间内... 注意赋初值,且若要为0 则赋值 0.0 而不是 0,因为这样更规范,例如要赋值3,则 赋值 3.0; 参与运算并把结果赋予点型时,我们要注意参与运算的值最少都要一个点型,不然结果是错误的; 1.  例子: #include<stdio.h> int main() float a = 0.0; // 0.0更规范 double b= 0.0; // 0.0更规.. public class ClassDemo { public static void main(String[] args) { int[] arr = {2, 4, 11, 0, -4, 333,... <br /><br />1. 如果赋值一个点数,必须在尾部加f。<br />例如 float  f = 123.456f;<br />因为如果不加f,java默认为double型,从double型到float型要强制类型转换赋值才行。<br /> <br />2. 如果赋值一个整数。可以不加f.java会自动转换int型到float型。<br />例如: float f = 126; 现象>>> 1.2 - 1.00.19999999999999996原因:根本原因:存在(用二进制存储时)“不可表示”,如0.1,0.2和0.01计算机会把你心里想的十进制小数转换为二进制小数,然后在内存中存储二进制小数CPython 中的 float 类型使用C语言的 double 类型进行存储。 float 对象的值是以固定的精度(通常为 53 位)存储的二进制点数,由于 ... 因为C++中float类型初始化(赋值)数据时,如果数据后面没有加f,系统会默认数据为double类型,当这个数据赋值给float类型时,系统会先把数据从double类型转换成float类型再把数据赋值给float类型定义的变量中。 如果你在数据的后面加上一个f时,系统默认为float类型,此时就不需要系统转换类型,可以直接赋值给float类型定义的变量中。从而减少一些不必要的工作,提高代码的质量和运行速度。 TC开发时(80年代)DOS下的存储资源紧缺,因此TC在编译时尽量不加入无关部分。在没发现需要做点转换时,就不将这个部分安装到可执行程序里。但有时TC不能正确识别实际确实需要点转换,因此就会出现上面错误。解决方法:设法告诉TC需要做点数输入转换。struct内的float不能用 scanf来读,是TC的一个Bug下面例子里增加了一个double变量并用它输入。大程序里由于变量很多,只要有了线...