我在c中进行多次转换?喜欢;
int a = foo ( ); float f = ( float ) a ;
但是,我还没弄清楚背景会发生什么.而且,为了更好地理解,我想手工完成转换.
编辑:如果您对转换了解很多,您还可以提供有关浮动到双转换的信息.而且,对于float到int
解决方法
>一个标志;
>一系列指数位e;和
>一系列尾数位m.
精度决定了指数和尾数有多少位可用.让我们检查单精度浮点的值0.1:
s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm 1/n 0 01111011 10011001100110011001101 ||||||||||||||||||||||+- 8388608 |||||||||||||||||||||+-- 4194304 ||||||||||||||||||||+--- 2097152 |||||||||||||||||||+---- 1048576 ||||||||||||||||||+----- 524288 |||||||||||||||||+------ 262144 ||||||||||||||||+------- 131072 |||||||||||||||+-------- 65536 ||||||||||||||+--------- 32768 |||||||||||||+---------- 16384 ||||||||||||+----------- 8192 |||||||||||+------------ 4096 ||||||||||+------------- 2048 |||||||||+-------------- 1024 ||||||||+--------------- 512 |||||||+---------------- 256 ||||||+----------------- 128 |||||+------------------ 64 ||||+------------------- 32 |||+-------------------- 16 ||+--------------------- 8 |+---------------------- 4 +----------------------- 2
标志是积极的,这很容易.
指数为64 32 16 8 2 1 = 123 – 127 bias = -4,因此乘数为2-4或1/16.偏见是存在的,这样你就可以获得非常小的数字(如10-30)以及大数字.
尾数很粗糙.它由1(隐式基数)加上(对于所有这些位,每个值为1 /(2n),因为n从1开始并向右增加),{1 / 2,1 / 16,1 / 32,1 / 256,1 / 512,1 / 4096,1 / 8192,1 / 65536,1 / 131072,1 / 1048576,1 / 97152,1 / 8388608}.
当你添加所有这些,你得到1.60000002384185791015625.
当你乘以2-4乘数时,得到0.100000001490116119384765625,这就是为什么他们说你不能完全代表0.1作为IEEE754浮点数.
在将整数转换为浮点数方面,如果尾数中包含尽可能多的位(包括隐式1),则只需传输整数位模式并选择正确的指数即可.不会有精度损失.例如,双精度IEEE754(64位,尾数为52/53)对32位整数没有任何问题.
如果整数中有更多位(例如32位整数和32位单精度浮点数,只有23/24位尾数),则需要缩放整数.
这涉及剥离最低有效位(实际上舍入),以使其适合尾数位.这当然会导致精度损失,但这是不可避免的.
让我们看一下特定的值123456789.以下程序转储每种数据类型的位.
#include <stdio.h> static void dumpBits (char *desc,unsigned char *addr,size_t sz) { unsigned char mask; printf ("%s:\n ",desc); while (sz-- != 0) { putchar (' '); for (mask = 0x80; mask > 0; mask >>= 1,addr++) if (((addr[sz]) & mask) == 0) putchar ('0'); else putchar ('1'); } putchar ('\n'); } int main (void) { int intNum = 123456789; float fltNum = intNum; double dblNum = intNum; printf ("%d %f %f\n",intNum,fltNum,dblNum); dumpBits ("Integer",(unsigned char *)(&intNum),sizeof (int)); dumpBits ("Float",(unsigned char *)(&fltNum),sizeof (float)); dumpBits ("Double",(unsigned char *)(&dblNum),sizeof (double)); return 0; }
我系统的输出如下:
123456789 123456792.000000 123456789.000000 integer: 00000111 01011011 11001101 00010101 float: 01001100 11101011 01111001 10100011 double: 01000001 10011101 01101111 00110100 01010100 00000000 00000000 00000000
我们会一次看这些.首先是整数,简单的两个幂:
00000111 01011011 11001101 00010101 ||| | || || || || | | | +-> 1 ||| | || || || || | | +---> 4 ||| | || || || || | +-----> 16 ||| | || || || || +----------> 256 ||| | || || || |+------------> 1024 ||| | || || || +-------------> 2048 ||| | || || |+----------------> 16384 ||| | || || +-----------------> 32768 ||| | || |+-------------------> 65536 ||| | || +--------------------> 131072 ||| | |+----------------------> 524288 ||| | +-----------------------> 1048576 ||| +-------------------------> 4194304 ||+----------------------------> 16777216 |+-----------------------------> 33554432 +------------------------------> 67108864 ========== 123456789
现在让我们看一下单精度浮点数.注意尾数的匹配模式匹配整数作为近乎完美的匹配:
mantissa: 11 01011011 11001101 00011 (spaced out). integer: 00000111 01011011 11001101 00010101 (untouched).
在尾数的左边有一个隐含的1位,它在另一端也被舍入,这是精度损失的来源(从上面那个程序的输出中,值从123456789变为123456792).
制定价值观:
s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm 1/n 0 10011001 11010110111100110100011 || | || |||| || | |+- 8388608 || | || |||| || | +-- 4194304 || | || |||| || +------ 262144 || | || |||| |+-------- 65536 || | || |||| +--------- 32768 || | || |||+------------ 4096 || | || ||+------------- 2048 || | || |+-------------- 1024 || | || +--------------- 512 || | |+----------------- 128 || | +------------------ 64 || +-------------------- 16 |+---------------------- 4 +----------------------- 2
标志是积极的.指数为128 16 8 1 = 153 – 127 bias = 26,因此乘数为226或67108864.
尾数是1(隐式基数)加(如上所述),1 / 4,1 / 64,1 / 128,1 / 1024,1 / 28,1,1 / 32768,1 / 262144,1 / 4194304,1 / 8388608}.当你添加所有这些,你得到1.83964955806732177734375.
当你乘以226乘数时,得到123456792,与程序输出相同.
双位掩码输出是:
s eeeeeeeeeee mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm 0 10000011001 1101011011110011010001010100000000000000000000000000
我不会经历弄清楚那个野兽的价值的过程:-)但是,我会在整数格式旁边显示尾数来显示公共位表示:
mantissa: 11 01011011 11001101 00010101 000...000 (spaced out). integer: 00000111 01011011 11001101 00010101 (untouched).
您可以再次看到左侧隐含位的共性和右侧的更大位可用性,这就是为什么在这种情况下不会丢失精度.
在浮动和双打之间转换方面,这也很容易理解.
首先必须检查特殊值,如NaN和无穷大.这些由特殊的指数/尾数组合表示,并且可能更容易检测这些前置角度,以新格式生成等效物.
那么在你从double到float的情况下,你显然可用的范围较小,因为指数中的位数较少.如果你的双精度超出浮动范围,你需要处理它.
假设它适合,那么你需要:
>改变指数(这两种类型的偏差是不同的).>从尾数中复制尽可能多的位(如果需要,可以舍入).>用零位填充剩余的目标尾数(如果有的话).