精华内容
下载资源
问答
  • 计算机内部的二进制浮点数加减运算 十进制科学计数法的加法例子 1.123×10^5 + 2.560×10^2 =1.123×10^5 + 0.002560×10^5 =1.12556×10^5 =1.126×10^5 进行尾数加减运算前,必须“对阶”!最后还要考虑舍入。 ...

    计算机内部的二进制浮点数加减运算

    十进制科学计数法的加法例子
    1.123×10^5 + 2.560×10^2
    =1.123×10^5 + 0.002560×10^5
    =1.12556×10^5
    =1.126×10^5
    进行尾数加减运算前,必须“对阶”!最后还要考虑舍入。
    计算机内部的二进制运算也是一样。
    “对阶”操作:目的是使两数的阶码相同。小阶向大阶看齐,阶小的那个数的尾数右移,右移位数等于两个阶码差的绝对值。
    IEEE 754尾数右移时,要将隐含的“1”移到小数部分,高位补0,移出低位保留到特定的“附加位”上。

    在这里插入图片描述
    例子1:用二进制浮点数形式计算 0.5+(-0.4375)
    解: 将两数转换为二进制
    0.5=1.000×2^-1 , -0.4375= -1.110×2^-2
    对阶:-1.110×2^-2 ——> -0.111×2^-1
    加减:1.000×2^-1 + (-0.111×2^-1)= 0.001×2^-1
    左规:0.001×2^-1 ——> 1.000×2^-4
    判断溢出:无
    结果:1.000×2^-4 = 0.0625

    例子2:用二进制浮点数形式计算 26.5+4.375
    解:将两数转换为二进制
    26.5=11010.1=1.10101×2^4
    4.375=100.011=1.00011×2^2
    对阶:1.00011×2^2 ——> 0.0100011×2^4
    相加:1.10101×2^4 + 0.0100011×2^4
    =1.1110111×2^4
    =30.875
    判断溢出:无

    若有错误的地方请各位指教。

    展开全文
  • 二进制浮点数减法运算

    千次阅读 多人点赞 2019-09-27 11:45:55
    二进制浮点数的规格化表示形式定义为N=2E⋅MN=2^E·MN=2E⋅M其中MMM称为尾数,EEE称为阶码 例如二进制浮点数11.011011的规格化表示形式为:2+0010×0.110110112^{+0010}×0.110110112+0010×0.11011011该浮点数在...

    二进制浮点数的规格化表示形式定义为 N = 2 E ⋅ M N=2^E·M N=2EM其中 M M M称为尾数, E E E称为阶码

    例如二进制浮点数11.011011的规格化表示形式为: 2 + 0010 × 0.11011011 2^{+0010}×0.11011011 2+0010×0.11011011该浮点数在计算机中存储为:

    00100011011011
    
    各个二进制位代表的含义为:
    阶符E | 阶码E | 尾符M | 尾码M
    00      010    00      11011011
    

    现假设有两浮点数 X X X Y Y Y
    X : 2 + 010 × 0.11011011 X:2^{+010}×0.11011011 X:2+010×0.11011011 Y : 2 + 100 × − 0.10101100 Y:2^{+100}×-0.10101100 Y2+100×0.10101100
    X X X Y Y Y在计算机中表示为:

        阶符E | 阶码E | 尾符M | 尾码M
    X   00      010    00      11011011
    Y   00      100    11      01010100
    

    要在计算机中实现加减法运算要执行5个步骤:

    1. 对阶

    对阶的目的是为了使两个阶数不同的浮点数变换到为可以直接相加,例如在十进制中 1.2 × 1 0 2 1.2×10^2 1.2×102 2.3 × 1 0 3 2.3×10^3 2.3×103的尾数是不能直接相加的,必须转换成相同的阶数才可以相加
    1.2 × 1 0 2 +   2.3 × 1 0 3 ‾ 3.3 × 1 0 ? ⟹ 0.12 × 1 0 3 +   2.3    × 1 0 3 ‾ 2.42 × 1 0 3 \begin{aligned} & \quad 1.2 × 10^2 \\ & \underline{+\ 2.3 × 10^3}\\ & \quad 3.3 × 10^?\\ \end{aligned}\Longrightarrow \begin{aligned} & \quad 0.12 × 10^3 \\ & \underline{+\ 2.3 \ \ × 10^3}\\ & \quad 2.42 × 10^3\\ \end{aligned} 1.2×102+ 2.3×1033.3×10?0.12×103+ 2.3  ×1032.42×103

    1.1 取大阶

    保留两个浮点数中阶码较大的那一个浮点数的阶数,较小阶码的浮点数的阶数在之后需要对齐大阶,取大阶的公式为: E m a x = max ⁡ ( E X , E Y ) E_{max} = \max(E_X,E_Y) Emax=max(EX,EY)之所以是取大阶而不是取小阶是因为,浮点数往小阶对其后,小数点会进入尾数之中,与上面举的例子不同,这种浮点数形式是无法在计算机中存储的。

    取大阶举例,对 X X X Y Y Y取大阶:
    E m a x = max ⁡ ( E X , E Y ) = E Y E_{max} = \max(E_X,E_Y)=E_Y Emax=max(EX,EY)=EY

    1.2 求阶差

    求出阶差后可以根据阶差对阶码小的浮点数的尾数进行调整,求阶差公式: Δ E = ∣ E X − E Y ∣ 补 \Delta E = |E_{X}-E_{Y}|_{补} ΔE=EXEY

    求阶差举例,对 X X X Y Y Y求阶差:
    Δ E = ∣ E X − E Y ∣ 补 = ∣ E X 补 − E Y 补 ∣ = ∣ E X 补 + ( − E Y ) 补 ∣ = ∣ 00010 + 11100 ∣ = ∣ 11110 ∣ = 2 \begin{aligned} \Delta E=& |E_{X}-E_{Y}|_{补}\\ =& |E_{X补}-E_{Y补}|\\ =& |E_{X补}+(-E_{Y})_{补}|\\ =& |00010 + 11100|\\ =& |11110|=2 \end{aligned} ΔE=====EXEYEXEYEX+(EY)00010+1110011110=2

    1.3 对阶

    1.2求阶差 Δ E ≠ 0 \Delta E \neq 0 ΔE=0,则执行对阶操作,将阶码值较小的浮点数尾数右移 Δ E \Delta E ΔE位,使得两个浮点数的阶码值相等。

    由于进行了右移,对阶操作往往会损失阶码值较小的浮点数的一部分精度从而产生计算误差,若要减小计算误差,则要将右移过程中损失的尾数值保留下了以供后面3.2.2左规格化和4.2舍入步骤使用,这里不细说。

    对阶举例,对 X X X Y Y Y对阶:
    已知 X X X Y Y Y的大阶阶码 E m a x = E Y E_{max}=E_Y Emax=EY,阶差 Δ E = 2 \Delta E=2 ΔE=2。即 E X E_X EX位向 E Y E_Y EY对齐,且 M X M_X MX右移 Δ E \Delta E ΔE位:
    00010 ‾ 00 11011011 ‾ ⟹ 00100 ‾ 00 00110110 ‾ \underline{00010}00\underline{11011011}\Longrightarrow\underline{00100}00\underline{00110110} 000100011011011001000000110110对阶后的 X X X Y Y Y:

        阶符E | 阶码E | 尾符M | 尾码M
    X   00      100    00      00110110
    Y   00      100    11      01010100
    

    对阶前的 X X X Y Y Y:

        阶符E | 阶码E | 尾符M | 尾码M
    X   00      010    00      11011011
    Y   00      100    11      01010100
    

    2. 尾数运算

    2.1 尾数运算

    对阶操作完成之后浮点数的尾数就可以进行运算了,公式可以表示为: M = [ ( M X ) ± ( M Y ) ] 补 M=[(M_X)\pm(M_Y)]_补 M=[(MX)±(MY)]

    尾数运算举例,对 X X X Y Y Y的尾数进行运算:
    M = [ ( M X ) + ( M Y ) ] 补 = ( M X ) 补 + ( M Y ) 补 M=[(M_X)+(M_Y)]_补=(M_X)_补+(M_Y)_补 M=[(MX)+(MY)]=(MX)+(MY)
    00100 0000110110 ‾ +   00100 1101010100 ‾ ‾ 00100 1110001010 ‾ \begin{aligned} & \quad 00100\underline{0000110110} \\ & \underline{+\ 00100\underline{1101010100}}\\ & \quad 00100\underline{1110001010}\\ \end{aligned} 001000000110110+ 001001101010100001001110001010

    3. 规格化

    3.1 判断尾数溢出

    双符号位的判断溢出方法:二进制数的符号一定为00(正)或11(负),运算后若符号位变为01则是正溢出,变为10则是负溢出,二进制数相加结果符号位溢出判断如下表所示:

    正数负数正溢负溢
    00110110

    可以简记为,符号位异或的结果为0则溢出,为1则不溢出。

    3.2 左右规格化
    3.2.1 右规格化

    若尾数加减后的结果 M M M溢出则执行右规格化操作,即尾数右移一位且阶码加1,表示为 M ≫ 1 , E + 1 M\gg 1,E+1 M1,E+1

    3.2.2 左规格化

    若尾数加减后的结果 M M M不溢出则执行左规格化操作,即尾数左移K位且阶码减K,表示为 M ≪ K , E − K M\ll K,E-K MK,EK其中 K K K表示将尾数数值最高位变为与尾数符号位不同值需要执行左移的次数。注意此处的左移要包括1.3对阶时被移出低位的尾数值。

    左规格化的目的是为了提高尾数的精度,例如, M = 001001110001010 M=001001110001010 M=001001110001010转为真值表示为 2 4 × − 0.01110110 2^4×-0.01110110 24×0.01110110,由于在计算机中尾数的存储位数有限,这种表示方法就会造成精度的下降,改为 2 3 × − 0.11101100 2^3×-0.11101100 23×0.11101100就可以多存一个位的数据

    尾数运算举例,对 M M M的尾数进行左规格化:
    尾数左移1位(括号中为对阶时被移出低位的尾数值): 1 11 ‾ 0001010 ( 11 ) ⟹ 1 10 ‾ 0010101 ( 1 ) 1\underline{11}0001010(11)\Longrightarrow 1\underline{10}0010101(1) 1110001010(11)1100010101(1)阶码减1: 00100 − 00001 = 00011 00100-00001=00011 0010000001=00011

    4. 舍入

    4.1 判断阶码溢出

    如果在上一步执行的是右规格化,则要判断阶码是否上溢,若执行的是左规格化,则要判断阶码是否下溢。

    判断方法与3.1一致,符号位异或的结果为0则溢出,为1则不溢出。右规格化若上溢则置上溢标志并且报运算结果溢出错误,左规格化若下溢则置机器零到5.4输出结果

    4.2 舍入

    若左右规格化的步骤执行后结果不溢出,则进行舍入处理。

    在执行3.2.1右规格化和1.3对阶时,尾数低位上的数值会被移除掉使得浮点数精度下降。舍入就是用来弥补被移除掉的精度,当移除掉的低位数值最高位为1时,在规格化后的尾数末尾加1,若加1后使得尾数溢出,则需再执行一次右规格化。

    舍入举例,对规格化后的 M M M的尾数进行舍入:
    在1.3对阶时被移除掉的两个低位数是11,则移除掉的低位数值最高位为1,应在规格化后的尾数末尾加1,得到: M = M + 1 = 1100010101 + 000000001 = 1100010110 M=M+1=1100010101+000000001=1100010110 M=M+1=1100010101+000000001=1100010110

    5. 判溢出

    5.1 判断尾数溢出

    执行完舍入之后,要判断舍入之后的尾数是否溢出,判断方法与3.1一致,符号位异或的结果为0则溢出,为1则不溢出。若不溢出则输出结果。

    若溢出则需要在执行一次右规格化,然后判断是否上溢,若上溢则置上溢标志并且报运算结果溢出错误,若不上溢则输出运算结果

    5.4 输出结果

    最终结果可以用 X ± Y X\pm Y X±Y来表示,其值就是EM的真值 X ± Y = E 真 × M 真 X\pm Y=E_真×M_真 X±Y=E×M

    结果举例,对规格化后的 M M M的尾数进行舍入:
    M = 1100010110 ⟹ X + Y = E 真 × M 真 = 2 011 × − 0.11101010 M=1100010110\Longrightarrow X+Y=E_真×M_真=2^{011}×-0.11101010 M=1100010110X+Y=E×M=2011×0.11101010

    展开全文
  • 浮点数的内存形式就不说了,就符号位,指数域,尾数域。 书本可以参考计算机体系结构 不多说,代码如下: // float.cpp: 定义控制台应用程序的入口点。 // #include "stdafx.h&...

    浮点数的内存形式就不说了,就符号位,指数域,尾数域。
    书本可以参考计算机体系结构
    不多说,代码如下:

    
    // float.cpp: 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include "string"
    #include "iostream"
    #include "iomanip"
    #include "stack"
    #include "queue"
    #include "math.h"
    
    using namespace std;
    
    struct Myfloat
    {
    	bool sign;
    	int enponential;
    	int leave;
    	Myfloat() { sign = 0; enponential = 0x00000000; leave = 0x00000000; };//两个构造函数
    	Myfloat(bool sign, int enponential, int leave) :sign(sign), enponential(enponential), leave(leave) {};
    };
    
    class yusuan
    {
    public:
    	yusuan();
    	~yusuan();
    	void get_string();//字符串输入
    	void to_Myfloat(Myfloat&, string&);//将字符串先转换为十进制,再转换为二进制
    	void to_Myfloat();//两次调用上一个函数
    	double relieve(Myfloat);//用公式将浮点数还原
    	static int to_right_one(int&);//右移一位,补0(其实没有必要)
    	static int to_right_one(int&, int);//右移多位,补0
    	static int to_left_one(int&);//左移一位,补0(其实没有必要)
    	static int to_right_one_add_one(int&);//右移一位,补1
    	static int to_left_one_add_one(int&);//左移一位,补1
    	static int get_one_compare(int);//去1,第n位为0,其他为1
    	static int onlyone_otherIsZero(int);//补1,第n位为1,其他为0
    	static Myfloat add(Myfloat&, Myfloat&);//加法
    	static Myfloat substruct(Myfloat&, Myfloat&);//减法
    	static Myfloat multiply(Myfloat&, Myfloat&);//乘法
    	static Myfloat divide(Myfloat&, Myfloat&);//除法
    
    	Myfloat one;//第一个数
    	Myfloat two;//第二个数
    	string s_one;//字符串1
    	string s_two;//字符串2
    };
    
    int yusuan::onlyone_otherIsZero(int n)
    {
    	int  ret = 0x80000000;
    	n--;
    	while (n--)
    	{
    		to_right_one(ret);
    	}
    	return ret;
    }
    
    Myfloat yusuan::divide(Myfloat& one_divide, Myfloat& two_divide)//二进制除法,不断地减,直到到23位
    {
    	Myfloat ret;
    	Myfloat t1(0, one_divide.enponential, one_divide.leave);
    	Myfloat t2(0, two_divide.enponential, two_divide.leave);
    
    	if (two_divide.enponential == 0x00000000 && two_divide.leave == 0x00000000)
    	{
    		cout << "被除数不能为0" << endl;
    	}
    	else
    	{
    		if (one_divide.sign && !two_divide.sign || !one_divide.sign&&two_divide.sign)
    		{
    			ret = divide(t1, t2);
    			ret.sign = 1;
    		}
    		else
    		{
    			ret.sign = 0;
    			ret.enponential = t1.enponential - t2.enponential + 127 + 2;
    			to_right_one_add_one(t1.leave);
    			to_right_one_add_one(t2.leave);
    			to_right_one(t1.leave);
    			to_right_one(t2.leave);
    			unsigned int leave1 = (unsigned int)t1.leave;
    			unsigned int leave2 = (unsigned int)t2.leave;
    			if (leave1 == leave2)
    			{
    				ret.leave = 0x00000000;
    			}
    			else
    			{
    				queue<bool> q;
    				while (q.size() <= 24)
    				{
    					if (leave1 == leave2)
    					{
    						q.push(1);
    						break;
    					}
    					else if (leave1 > leave2)
    					{
    						q.push(1);
    						leave1 -= leave2;
    					}
    					else
    					{
    						q.push(0);
    					}
    					leave1 <<= 1;
    					leave1 &= 0xfffffffe;
    				}
    				while (q.front() == 0 && !q.empty())
    				{
    					ret.enponential--;
    					q.pop();
    				}
    				if (!q.empty())
    				{
    					q.pop();
    					int temp = 0x80000000;
    					while (!q.empty())
    					{
    						if (q.front())
    						{
    							ret.leave |= temp;
    						}
    						q.pop();
    						to_right_one(temp);
    					}
    				}
    				else
    				{
    					cout << "Something wrong!" << endl;
    				}
    			}
    			ret.enponential -= 2;
    		}
    	}
    	return ret;
    }
    
    int yusuan::to_right_one(int& temp, int n)
    {
    	while (n--)
    	{
    		to_right_one(temp);
    	}
    	return temp;
    }
    
    int yusuan::get_one_compare(int n)
    {
    	int ret = 0x7fffffff;
    	n--;
    	while (n--)
    	{
    		to_right_one_add_one(n);
    	}
    	return ret;
    }
    
    Myfloat yusuan::multiply(Myfloat& one_multiply, Myfloat& two_multiply)//二进制乘法
    {
    	Myfloat ret;
    	Myfloat t1(0, one_multiply.enponential, one_multiply.leave);
    	Myfloat t2(0, two_multiply.enponential, two_multiply.leave);
    	int weight = 0;
    
    	if ((!one_multiply.sign&&two_multiply.sign) || (one_multiply.sign && !two_multiply.sign))
    	{
    		ret = multiply(t1, t2);
    		ret.sign = 1;
    	}
    	else
    	{
    		ret.sign = 0;
    		ret.enponential = t1.enponential + t2.enponential - 127 + 2;
    		to_right_one_add_one(t1.leave);
    		to_right_one_add_one(t2.leave);
    		unsigned long long leave1 = 0;
    		leave1 |= (unsigned long long)t1.leave;
    		leave1 &= 0x00000000ffffffff;
    		unsigned long long leave2 = 0;
    		leave2 |= (unsigned long long)t2.leave;
    		leave2 &= 0x00000000ffffffff;
    		unsigned long long add = leave1 << 23;
    		unsigned long long compare = 0x0000000000000100;
    		for (int i = 0; i < 24; i++)
    		{
    			if (compare&leave2)
    			{
    				leave1 += add;
    			}
    			leave1 >>= 1;
    			leave2 >>= 1;
    		}
    		leave1 <<= 1;
    		compare = 0x0080000000000000;
    		add = 0x80000000;
    		for (int i = 0; i < 24; i++)
    		{
    			if (compare&leave1)
    			{
    				ret.leave |= add;
    			}
    			compare >>= 1;
    			add >>= 1;
    		}
    		for (int i = 0; i < 23; i++)
    		{
    			if (ret.leave & 0x80000000)
    			{
    				ret.enponential--;
    				to_left_one(ret.leave);
    				break;
    			}
    			ret.enponential--;
    			to_left_one(ret.leave);
    		}
    	}
    
    	return ret;
    }
    
    int yusuan::to_right_one_add_one(int& temp)
    {
    	temp >>= 1;
    	temp |= 0x80000000;
    	return temp;
    }
    
    
    int yusuan::to_left_one_add_one(int& temp)
    {
    	temp <<= 1;
    	temp |= 0x00000001;
    	return temp;
    }
    
    Myfloat yusuan::substruct(Myfloat& one_substruct, Myfloat& two_substruct)
    {
    	Myfloat ret;
    
    	if (one_substruct.sign && !two_substruct.sign)//负减正
    	{
    		ret = two_substruct;
    		ret.sign = 1;
    		return add(one_substruct, ret);
    	}
    	else if (!one_substruct.sign && two_substruct.sign)//正减负
    	{
    		ret = two_substruct;
    		ret.sign = 0;
    		return add(one_substruct, ret);
    	}
    	else if (one_substruct.sign && two_substruct.sign)//负减负
    	{
    		ret = two_substruct;
    		ret.sign = 0;
    		Myfloat change(0, one_substruct.enponential, one_substruct.leave);
    		return substruct(ret, change);
    	}
    	else//正减正
    	{
    		ret.sign = one_substruct.sign;
    		int diffierent_of_enponential;
    		int one_of_enponential = one_substruct.enponential - 127;
    		int two_of_enponential = two_substruct.enponential - 127;
    
    		diffierent_of_enponential = one_of_enponential - two_of_enponential;
    		if (diffierent_of_enponential > 0)
    		{
    			Myfloat move_binary(two_substruct.sign, two_substruct.enponential, two_substruct.leave);
    			to_right_one_add_one(move_binary.leave);
    			move_binary.enponential++;
    			diffierent_of_enponential--;
    			for (int i = 0; i < diffierent_of_enponential; i++)
    			{
    				move_binary.enponential++;
    				to_right_one(move_binary.leave);
    			}
    			ret.sign = one_substruct.sign;
    			to_right_one_add_one(one_substruct.leave);
    			ret.enponential = one_substruct.enponential + 1;
    			to_right_one(move_binary.leave);
    			ret.leave = one_substruct.leave - move_binary.leave;
    			to_left_one(one_substruct.leave);
    		}
    		else if (diffierent_of_enponential < 0)//可以调换位置,再调用substruct,变符号
    		{
    			Myfloat move_binary(one_substruct.sign, one_substruct.enponential, one_substruct.leave);
    			to_right_one_add_one(move_binary.leave);
    			move_binary.enponential++;
    			diffierent_of_enponential++;
    			for (int i = 0; i < (-diffierent_of_enponential); i++)
    			{
    				move_binary.enponential++;
    				to_right_one(move_binary.leave);
    			}
    			ret.sign = 1;
    			to_right_one_add_one(two_substruct.leave);
    			ret.enponential = two_substruct.enponential + 1;
    			to_right_one(move_binary.leave);
    			ret.leave = two_substruct.leave - move_binary.leave;
    			to_left_one(two_substruct.leave);
    		}
    		else
    		{
    			ret.enponential = one_substruct.enponential;
    			to_right_one_add_one(one_substruct.leave);
    			to_right_one_add_one(two_substruct.leave);
    			ret.enponential++;
    			if (one_substruct.leave>two_substruct.leave)
    			{
    				ret.leave = one_substruct.leave - two_substruct.leave;
    			}
    			else
    			{
    				ret.leave = two_substruct.leave - one_substruct.leave;
    				ret.sign = 1;
    			}
    			to_left_one(one_substruct.leave);
    			to_left_one(two_substruct.leave);
    		}
    		for (int i = 0; i < 23; i++)
    		{
    			if (ret.leave & 0x80000000)
    			{
    				ret.enponential--;
    				to_left_one(ret.leave);
    				break;
    			}
    			ret.enponential--;
    			to_left_one(ret.leave);
    		}
    	}
    
    	return ret;
    }
    
    Myfloat yusuan::add(Myfloat& one_add, Myfloat& two_add)
    {
    	Myfloat ret;
    
    	if (one_add.sign && !two_add.sign)//负加正
    	{
    		ret = one_add;
    		ret.sign = 0;
    		return substruct(two_add, ret);
    	}
    	else if (!one_add.sign && two_add.sign)//正加负
    	{
    		ret = two_add;
    		ret.sign = 0;
    		return substruct(one_add, ret);
    	}
    	else if (one_add.sign && two_add.sign)//负加负
    	{
    		ret = one_add;
    		ret.sign = 0;
    		Myfloat change(0, two_add.enponential, two_add.leave);
    		ret = add(ret, change);
    		ret.sign = 1;
    		return ret;
    	}
    	else
    	{
    		int diffierent_of_enponential;
    
    		ret.sign = one_add.sign;
    
    		int one_of_enponential = one_add.enponential - 127;
    		int two_of_enponential = two_add.enponential - 127;
    
    		diffierent_of_enponential = one_of_enponential - two_of_enponential;
    		if (diffierent_of_enponential > 0)
    		{
    			Myfloat move_binary(two_add.sign, two_add.enponential, two_add.leave);
    			to_right_one_add_one(move_binary.leave);
    			move_binary.enponential++;
    			diffierent_of_enponential--;
    			for (int i = 0; i < diffierent_of_enponential; i++)
    			{
    				move_binary.enponential++;
    				to_right_one(move_binary.leave);
    			}
    			ret.enponential = one_add.enponential + 2;
    			to_right_one_add_one(one_add.leave);
    			to_right_one(move_binary.leave);
    			ret.leave = to_right_one(one_add.leave) + to_right_one(move_binary.leave);
    			to_left_one(one_add.leave);
    			to_left_one(one_add.leave);
    		}
    		else if (diffierent_of_enponential < 0)//可以one和two换位置,用上面的计算
    		{
    			Myfloat move_binary(one_add.sign, one_add.enponential, one_add.leave);
    			to_right_one_add_one(move_binary.leave);
    			move_binary.enponential++;
    			diffierent_of_enponential++;
    			for (int i = 0; i < (-diffierent_of_enponential); i++)
    			{
    				move_binary.enponential++;
    				to_right_one(move_binary.leave);
    			}
    			ret.enponential = two_add.enponential + 2;
    			to_right_one_add_one(two_add.leave);
    			to_right_one(move_binary.leave);
    			ret.leave = to_right_one(two_add.leave) + to_right_one(move_binary.leave);
    			to_left_one(two_add.leave);
    			to_left_one(two_add.leave);
    		}
    		else
    		{
    			ret.enponential = one_add.enponential + 2;
    			to_right_one_add_one(one_add.leave), to_right_one_add_one(two_add.leave);
    			ret.leave = to_right_one(one_add.leave) + to_right_one(two_add.leave);
    			to_left_one(one_add.leave);
    			to_left_one(two_add.leave);
    			to_left_one(one_add.leave);
    			to_left_one(two_add.leave);
    		}
    		for (int i = 0; i < 23; i++)
    		{
    			if (ret.leave & 0x80000000)
    			{
    				ret.enponential--;
    				to_left_one(ret.leave);
    				break;
    			}
    			ret.enponential--;
    			to_left_one(ret.leave);
    		}
    	}
    	return ret;
    }
    
    double yusuan::relieve(Myfloat f)//不要传引用,传值
    {
    	double ret = 1;
    	int compare = 0x80000000;
    
    	if (f.enponential == 0x00000000 && f.leave == 0x00000000)return 0;
    
    	int enponential = f.enponential - 127;
    
    	ret *= pow(2, enponential--);
    	for (int i = 0; i < 32; i++)
    	{
    		if (compare&f.leave)
    		{
    			ret += pow(2, enponential);
    		}
    		enponential--;
    		to_right_one(compare);
    	}
    	return f.sign ? -ret : ret;
    }
    
    int yusuan::to_right_one(int& temp)
    {
    	temp >>= 1;
    	temp &= 0x7fffffff;
    	return temp;
    }
    
    int yusuan::to_left_one(int& temp)
    {
    	temp <<= 1;
    	temp &= 0xfffffffe;
    	return temp;
    }
    
    void yusuan::to_Myfloat()
    {
    	to_Myfloat(one, s_one);
    	to_Myfloat(two, s_two);
    }
    
    void yusuan::to_Myfloat(Myfloat& f, string &s)
    {
    	char point;
    	stack<bool> t;
    	int temp = 0;
    
    	point = (char)s.find('.');
    	if (s.at(0) == '0' && point == string::npos)
    	{
    		f.enponential = 0x00000000;
    		f.leave = 0x00000000;
    		return;
    	}
    	if (s.at(0) != '-')
    	{
    		f.sign = 0;
    		if (point == string::npos)//整数
    		{
    			for (int i = 0; i < s.size(); i++)//
    			{
    				temp = temp * 10 + s.at(i) - '0';
    			}
    			while (temp != 0)
    			{
    				t.push(temp % 2);
    				temp /= 2;
    			}
    			f.enponential = t.size();//指数
    			temp = 0x80000000;
    			t.pop();
    			for (int i = 0; !t.empty(); i++)
    			{
    				if (t.top())
    				{
    					f.leave |= temp;
    				}
    				t.pop();
    				to_right_one(temp);
    			}
    		}
    		else
    		{
    			queue<bool> q;
    			int compare = 0;
    			for (int i = 0; i < point; i++)
    			{
    				temp = temp * 10 + s.at(i) - '0';
    			}
    			while (temp != 0)
    			{
    				t.push(temp % 2);
    				temp /= 2;
    			}
    			f.enponential = t.size();//未调整指数
    			for (int i = 0; i < s.size() - point - 1; i++)
    			{
    				temp = temp * 10 + s.at(point + 1 + i) - '0';//将小数string化为整数乘2,不用float
    				compare = i + 1;//记录位数
    			}
    			compare = (int)pow(10, compare);
    			for (int j = 0; j < 23; j++)//尾部
    			{
    				temp *= 2;
    				if (temp == compare)
    				{
    					q.push(1);
    					break;
    				}
    				else if (temp > compare)
    				{
    					q.push(1);
    					temp -= compare;
    				}
    				else
    				{
    					q.push(0);
    				}
    			}
    			int i;
    			temp = 0x80000000;
    			if (f.enponential != 0)
    			{
    				t.pop();
    				for (i = 0; !t.empty() && i <= 23; i++)
    				{
    					if (t.top())
    					{
    						f.leave |= temp;
    					}
    					t.pop();
    					to_right_one(temp);
    				}
    			}
    			else
    			{
    				while (q.front() != 1)
    				{
    					f.enponential--;
    					q.pop();
    				}
    				q.pop();
    				i = 0;
    			}
    			for (; !q.empty() && i <= 23; i++)
    			{
    				if (q.front())
    				{
    					f.leave |= temp;
    				}
    				to_right_one(temp);
    				q.pop();
    			}
    		}
    		f.enponential = f.enponential - 1 + 127;
    	}
    	else
    	{
    		s.erase(0, 1);
    		to_Myfloat(f, s);
    		f.sign = 1;
    	}
    }
    
    void yusuan::get_string()
    {
    	cout << "请输入第一个数:";
    	cin >> s_one;
    	cout << "请输入第二个数:";
    	cin >> s_two;
    }
    
    yusuan::yusuan()
    {
    }
    
    yusuan::~yusuan()
    {
    }
    
    int main()
    {
    	yusuan test;
    
    	test.get_string();
    	cout << test.s_one << "  " << test.s_two << endl;
    
    	test.to_Myfloat();
    	cout << test.one.sign << " " << test.one.enponential << " " << test.one.leave << endl;
    	cout << fixed << setprecision(7) << test.relieve(test.one) << endl;
    	cout << test.two.sign << " " << test.two.enponential << " " << test.two.leave << endl;
    	cout << fixed << setprecision(7) << test.relieve(test.two) << endl;
    
    	cout << fixed << setprecision(7) << "加法:" << test.relieve(test.add(test.one, test.two)) << endl;
    	cout << fixed << setprecision(7) << "减法:" << test.relieve(test.substruct(test.one, test.two)) << endl;
    	cout << fixed << setprecision(7) << "乘法:" << test.relieve(test.multiply(test.one, test.two)) << endl;
    	cout << fixed << setprecision(7) << "除法:" << test.relieve(test.divide(test.one, test.two)) << endl;
    
    	system("pause");
    
    	return 0;
    }
    
    
    

    主要运用位操作(C语言),浮点数内存形式,二进制加减乘除(计算机体系结构)。

    展开全文
  • IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊...

    IEEE二进制浮点数算术标准IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。

    IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。只有32位模式有强制要求,其他都是选择性的。大部分编程语言都有提供IEEE浮点数格式与算术,但有些将其列为非必需的。例如,IEEE 754问世之前就有的C语言,现在有包括IEEE算术,但不算作强制要求(C语言的float通常是指IEEE单精确度,而double是指双精确度)。

    该标准的全称为IEEE二进制浮点数算术标准(ANSI/IEEE Std 754-1985),又称IEC 60559:1989,微处理器系统的二进制浮点数算术(本来的编号是IEC 559:1989)[1]。后来还有“与基数无关的浮点数”的“IEEE 854-1987标准”,有规定基数为2跟10的状况。现在最新标准是“ISO/IEC/IEEE FDIS 60559:2010”。

    在六、七十年代,各家计算机公司的各个型号的计算机,有着千差万别的浮点数表示,却没有一个业界通用的标准。这给数据交换、计算机协同工作造成了极大不便。IEEE的浮点数专业小组于七十年代末期开始酝酿浮点数的标准。在1980年,英特尔公司就推出了单片的8087浮点数协处理器,其浮点数表示法及定义的运算具有足够的合理性、先进性,被IEEE采用作为浮点数的标准,于1985年发布。而在此前,这一标准的内容已在八十年代初期被各计算机公司广泛采用,成了事实上的业界工业标准。加州大学伯克利分校的数值计算与计算机科学教授威廉·卡韩被誉为“浮点数之父”。

    浮点数剖析[编辑]

    以下是该标准对浮点数格式的描述。

    本文表示比特的约定[编辑]

    把W个比特(bit)的数据,从内存地址低端到高端,以0到W−1编码。通常将内存地址低端的比特写在最右边,称作最低有效位(Least Significant Bit,LSB),代表最小的比特,改变时对整体数值影响最小的比特。声明这一点的必要性在于X86体系架构是小端序的数据存储。

    对于十进制整数N,必要时表示为N10以与二进制的数的表示N2相区分。

    对于一个数,其二进制科学计数法表示下的指数的值,下文称之为指数的实际值;而根据IEEE 754标准对指数部分的编码的值,称之为浮点数表示法指数域的编码值

    整体呈现[编辑]

    IEEE 754浮点数的三个域

    二进制浮点数是以符号数值表示法的格式存储——最高有效位被指定为符号位(sign bit);“指数部分”,即次高有效的e个比特,存储指数部分;最后剩下的f个低有效位的比特,存储“有效数”(significand)的小数部分(在非规约形式下整数部分默认为0,其他情况下一律默认为1)。

    指数偏移值[编辑]

    指数偏移值(exponent bias),是指浮点数表示法中的指数域的编码值为指数的实际值加上某个固定的值,IEEE 754标准规定该固定值为2e-1 - 1[2],其中的e为存储指数的比特的长度。

    以单精度浮点数为例,它的指数域是8个比特,固定偏移值是28-1 - 1 = 128−1 = 127.单精度浮点数的指数部分实际取值是从128到-127。例如指数实际值为1710,在单精度浮点数中的指数域编码值为14410,即14410 = 1710 + 12710.

    采用指数的实际值加上固定的偏移值的办法表示浮点数的指数,好处是可以用长度为e个比特的无符号整数来表示所有的指数取值,这使得两个浮点数的指数大小的比较更为容易,实际上可以按照字典序比较两个浮点表示的大小。

    这种移码表示的指数部分,中文称作阶码

    规约形式的浮点数[编辑]

    如果浮点数中指数部分的编码值在0 < exponent < 2e-1之间,且尾数部分最高有效位(即整数字)是1,那么这个浮点数将被称为规约形式的浮点数。“规约”是指用唯一确定的浮点形式去表示一个值。

    由于这种表示下的尾数有一位隐含的二进制有效数字,为了与二进制科学计数法的尾数(mantissa)相区别,IEEE754称之为有效数(significant)。

    非规约形式的浮点数[编辑]

    如果浮点数的指数部分的编码值是0,尾数为非零,那么这个浮点数将被称为非规约形式的浮点数。IEEE 754标准规定:非规约形式的浮点数的指数偏移值比规约形式的浮点数的指数偏移值大1.例如,最小的规约形式的单精度浮点数的指数部分编码值为1,指数的实际值为-126;而非规约的单精度浮点数的指数域编码值为0,对应的指数实际值也是-126而不是-127。实际上非规约形式的浮点数仍然是有效可以使用的,只是它们的绝对值已经小于所有的规约浮点数的绝对值;即所有的非规约浮点数比规约浮点数更接近0。规约浮点数的尾数大于等于1且小于2,而非规约浮点数的尾数小于1且大于0.

    除了规约浮点数,IEEE754-1985标准采用非规约浮点数,用来解决填补绝对值意义下最小规格数与零的距离。(举例说,正数下,最大的非规格数等于最小的规格数。而一个浮点数编码中,如果exponent=0,且尾数部分不为零,那么就按照非规约浮点数来解析) 非规约浮点数源于70年代末IEEE浮点数标准化专业技术委员会酝酿浮点数二进制标准时,Intel公司渐进式下溢出(gradual underflow)的力荐。当时十分流行的DEC VAX机的浮点数表示采用了突然式下溢出(abrupt underflow)。如果没有渐进式下溢出,那么0与绝对值最小的浮点数之间的距离(gap)将大于相邻的小浮点数之间的距离。例如单精度浮点数的绝对值最小的规约浮点数是{\displaystyle 1.0\times 2^{-126}}1.0\times 2^{​{-126}},它与绝对值次小的规约浮点数之间的距离为{\displaystyle 2^{-126}\times 2^{-23}=2^{-149}}2^{​{-126}}\times 2^{​{-23}}=2^{​{-149}}。如果不采用渐进式下溢出,那么绝对值最小的规约浮点数与0的距离是相邻的小浮点数之间距离的{\displaystyle 2^{23}}2^{​{23}}倍!可以说是非常突然的下溢出到0。这种情况的一种糟糕后果是:两个不等的小浮点数X与Y相减,结果将是0.训练有素的数值分析人员可能会适应这种限制情况,但对于普通的程序员就很容易陷入错误了。采用了渐进式下溢出后将不会出现这种情况。例如对于单精度浮点数,指数部分实际最小值是(-126),对应的尾数部分从{\displaystyle 1.1111\ldots 11}1.1111\ldots 11{\displaystyle 1.1111\ldots 10}1.1111\ldots 10一直到{\displaystyle 0.0000\ldots 10}0.0000\ldots 10{\displaystyle 0.0000\ldots 01}0.0000\ldots 01{\displaystyle 0.0000\ldots 00}0.0000\ldots 00相邻两小浮点数之间的距离(gap)都是{\displaystyle 2^{-126}\times 2^{-23}=2^{-149}}2^{​{-126}}\times 2^{​{-23}}=2^{​{-149}};而与0最近的浮点数(即最小的非规约数)也是{\displaystyle 2^{-126}\times 2^{-23}=2^{-149}}2^{​{-126}}\times 2^{​{-23}}=2^{​{-149}}

    特殊值[编辑]

    这里有三个特殊值需要指出:

    1. 如果指数是0并且尾数的小数部分是0,这个数±0(和符号位相关)
    2. 如果指数 = {\displaystyle 2^{e}-1}2^{​{e}}-1并且尾数的小数部分是0,这个数是±(同样和符号位相关)
    3. 如果指数 = {\displaystyle 2^{e}-1}2^{​{e}}-1并且尾数的小数部分非0,这个数表示为不是一个数(NaN)

    以上规则,总结如下:

    形式 指数 小数部分
    00
    非规约形式0非0
    规约形式{\displaystyle 1}1{\displaystyle 2^{e}-2}2^{e}-2任意
    无穷{\displaystyle 2^{e}-1}2^{e}-10
    NaN{\displaystyle 2^{e}-1}2^{e}-1非零

    32位单精度[编辑]

    单精度二进制小数,使用32个比特存储。

    1823位长
    SExpFraction
    3130至23
    偏正值(实际的指数大小+127)
    22至0位编号(从右边开始为0)

    S为符号位,Exp为指数字,Fraction为有效数字。 指数部分即使用所谓的偏正值形式表示,偏正值为实际的指数大小与一个固定值(32位的情况是127)的和。采用这种方式表示的目的是简化比较。因为,指数的值可能为正也可能为负,如果采用补码表示的话,全体符号位S和Exp自身的符号位将导致不能简单的进行大小比较。正因为如此,指数部分通常采用一个无符号的正数值存储。单精度的指数部分是−126~+127加上偏移值127,指数值的大小从1~254(0和255是特殊值)。浮点小数计算时,指数值减去偏正值将是实际的指数大小。

    单精度浮点数各种极值情况:

    类别 正负号 实际指数 有偏移指数 指数域 尾数域 数值
    0-127 00000 0000000 0000 0000 0000 0000 00000.0
    负零 1-127 00000 0000000 0000 0000 0000 0000 0000−0.0
    1 00 1270111 1111000 0000 0000 0000 0000 00001.0
    -1 10 1270111 1111000 0000 0000 0000 0000 0000−1.0
    最小的非规约数 *-126 00000 0000000 0000 0000 0000 0000 0001±2−23 × 2−126 = ±2−149 ≈ ±1.4×10-45
    中间大小的非规约数 *-126 00000 0000100 0000 0000 0000 0000 0000±2−1 × 2−126 = ±2−127 ≈ ±5.88×10-39
    最大的非规约数 *-126 00000 0000111 1111 1111 1111 1111 1111±(1−2−23) × 2−126 ≈ ±1.18×10-38
    最小的规约数 *-126 10000 0001000 0000 0000 0000 0000 0000±2−126 ≈ ±1.18×10-38
    最大的规约数 *127 2541111 1110111 1111 1111 1111 1111 1111±(2−2−23) × 2127 ≈ ±3.4×1038
    正无穷 0128 2551111 1111000 0000 0000 0000 0000 0000+∞
    负无穷 1128 2551111 1111000 0000 0000 0000 0000 0000−∞
    NaN *128 2551111 1111non zeroNaN
    * 符号位可以为0或1 .

    64位双精度[编辑]

    双精度二进制小数,使用64个比特存储。

    11152位长
    SExpFraction
    6362至52
    偏正值(实际的指数大小+1023)
    51至0位编号(从右边开始为0)

    S为符号位,Exp为指数字,Fraction为有效数字。指数部分即使用所谓的偏正值形式表示,偏正值为实际的指数大小与一个固定值(64位的情况是1023)的和。采用这种方式表示的目的是简化比较。因为,指数的值可能为正也可能为负,如果采用补码表示的话,全体符号位S和Exp自身的符号位将导致不能简单的进行大小比较。正因为如此,指数部分通常采用一个无符号的正数值存储。双精度的指数部分是−1022~+1023加上1023,指数值的大小从1~2046(0(2进位全为0)和2047(2进位全为1)是特殊值)。浮点小数计算时,指数值减去偏正值将是实际的指数大小。

    浮点数的比较[编辑]

    浮点数基本上可以按照符号位、指数域、尾数域的顺序作字典比较。显然,所有正数大于负数;正负号相同时,指数的二进制表示法更大的其浮点数值更大。

    浮点数的舍入[编辑]

    任何有效数上的运算结果,通常都存放在较长的寄存器中,当结果被放回浮点格式时,必须将多出来的比特丢弃。 有多种方法可以用来运行舍入作业,实际上IEEE标准列出4种不同的方法:

    • 舍入到最接近:舍入到最接近,在一样接近的情况下偶数优先(Ties To Even,这是默认的舍入方式):会将结果舍入为最接近且可以表示的值,但是当存在两个数一样接近的时候,则取其中的偶数(在二进制中式以0结尾的)。
    • 朝+∞方向舍入:会将结果朝正无限大的方向舍入。
    • 朝-∞方向舍入:会将结果朝负无限大的方向舍入。
    • 朝0方向舍入:会将结果朝0的方向舍入。

    浮点数的运算与函数[编辑]

    标准运算[编辑]

    下述函数必须提供:

    • 加减乘除Add, subtract, multiply, divide.在加减运算中负零与零相等 -0.0 = 0.0
    • 平方根Square root. sqrt(x) ≥ 0 (x≥0),另规定sqrt(-0.0) = -0.0
    • 浮点余数。返回值x - (round(x / y) * y).
    • 近似到最近的整数round(x).如果恰好在两个相邻整数之间,则近似到偶数。
    • 比较运算. -Inf <负的规约浮点数数<负的非规约浮点数< -0.0 = 0.0 <正的非规约浮点数<正的规约浮点数< Inf;

    特殊比较: -Inf = -Inf, Inf = Inf, NaN与任何浮点数(包括自身)的比较结果都为假,即 (NaN ≠ x) = false.

    建议的函数与谓词[编辑]

    • copysign(x, y)copysign(x, y)返回的值由x的不带符号的部分和y的符号组成。因此abs(x)等于copysign(x, 1.0)copysign可以对NaN正确操作,这是少有的几个可以对NaN像普通算术一样操作有效的函数之一。C99新增了copysign函数。
    • −x:从涵义上指将x的符号反转。当x是±0或者NaN时,其涵义可能不同于0-x.
    • scalb(y, N):计算y×2N(N是整数),无需再计算2N。C99中对应的函数名是scalbn.
    • logb(x):计算x = 1.a×2n(x ≠ 0, a ∈[0, 1))中的n. C99新增了logbilogb函数。
    • nextafter(x,y):沿y方向找最邻近x的可表达浮点数。比如nextafter(0, 1)得到的是最小可表达的正数。C99新增了nextafter函数。
    • finite(x):判断x是否有限,即−Inf < x < Inf. C99新增了isfinite函数。
    • isnan(x):判断x是否是一个NaN,这等价于"x ≠ x". C99新增了isnan函数。
    • x <> y:仅当x < y或者x > y时才为True,其涵义是NOT(x = y)。注意这不同于"x ≠ x"。
    • unordered(x, y):当x与y无法比较大小时为True,比如说x或者y是一个NaN. C99中对应的函数名是isunordered.
    • class(x):区分x的浮点数类属:信号NaN、静默NaN、-Inf、负的规约浮点数,负的非规约浮点数,-0.0,0.0,正的非规约浮点数,正的规约浮点数,Inf。

    精度[编辑]

    二进制,第一个有效数字必定是“1”,因此这个“1”并不会存储。

    单精和双精浮点数的有效数字分别是有存储的23和52个位,加上最左手边没有存储的第1个位,即是24和53个位。

    {\displaystyle \log 2^{24}=7.22} \log 2^{​{24}}=7.22
    {\displaystyle \log 2^{53}=15.95} \log 2^{​{53}}=15.95

    由以上的计算,单精和双精浮点数可以保证7位和15位十进制有效数字。


    以下的C++程序,概略地展示了单精和双精浮点数的精度。

    #include <iostream>
    
    int main () {
        std::cout.precision(20);
        float a=123.45678901234567890;
        double b=123.45678901234567890;
        std::cout << a << std::endl;
        std::cout << b << std::endl;
        return 0;
    }
    
    // Xcode 5.1
    // Output:
    // 123.456787109375
    // 123.45678901234568059
    // Program ended with exit code: 0
    展开全文
  • 计算机基础:19、二进制--浮点数的加减法运算浮点数加减法1.1、对阶1.2、尾数求和1.3、尾数规格化(左移)1.4、尾数规格化(右移)1.4.1、舍入1.5、溢出判断2、浮点数加减法总结 浮点数加减法 浮点数加减法公式如下...
  • 二进制浮点数算术标准 IEEE 754

    千次阅读 2013-03-14 10:10:34
    IEEE二进制浮点数算术标准(IEEE 754)是1980年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值...
  • 补码二、浮点数二进制表示 前言 对于该代码 public class hello { public static void main(String[] args) { int a = -17; System.out.println("二进制输出"+Integer.toBinaryString(a)); int b = 17; ...
  • js浮点数加减乘除

    千次阅读 2018-08-02 10:52:08
    js浮点数加减乘除 js浮点数的加减乘除存在着严重的bug,例如:在google浏览器下,0.1+0.2=0.30000000000000004;这完全不是我们想要的结果。 对于这一问题的解决方案就是重写浮点数的加减乘除方法,其原理是现将...
  • 二进制存储浮点数不精确问题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、...
  • 我们先来罗列一下前四篇:谈谈二进制(一)谈谈二进制(二)——四则运算谈谈二进制(三)——位运算及其应用谈谈二进制(四)——原码、补码、反码、移码其中,在上一篇里,我们认识了四种机器数,它们各司其职,但总的来说...
  • x=1.000*2^-1, y=-0.111*2^-1,x和y都是二进制数,x和y的补码怎么求,x+y怎么算,希望有详细过程
  • 关于字节与位: 一个int占4个字节(byte),一个字节占8位(bit),所以一个int占用4x8=32位。 char类型的范围为什么是-128~127? 有一个整型范围的公式:-2^(n-...char占8位,用二进制表示为 0000 0000 ~ 1111 111...
  • 计算机基础——浮点数加减运算

    千次阅读 2018-12-25 21:51:31
    •十进制科学计数法的加法例子 1.123 × 10^5 + 2.560 ×10^ 其计算过程为: 1.123 ×10^5 + 2.560 ×10^2 = 1.123 ×10^5 + 0.002560 ×10^5  =(1.123 + 0.00256) ×10^5  ...
  • 计算机中的字由位组成,字又是用二进制表示,那么我们该如何进行二进制加减乘除运算呢?要搞清这个问题,首先得知道计算机中实数和浮点数的表示方法,定点表示和浮点表示等,详情见我专栏中另一篇博文。 弄清楚了...
  • IEEE 754 浮点数加减运算

    千次阅读 2020-04-22 23:23:21
    AE ]移 - [ BE ]移 + 127 = ( [AE]移 - [BE]移 + 127 ) mod 28 浮点数加减 设: A = 2AE × AM,B = 2BE × BM AE、BE为阶码,AM、BM为尾数 舍入 右移时: 0舍1入 末位恒置1 例题 x = 0.5, y = 0.4375, 32位单精度...
  • 浮点数加减乘除

    千次阅读 2018-11-07 09:40:20
     * floatTool 包含加减乘除四个方法,能确保浮点数运算不丢失精度  *  * 我们知道计算机编程语言里浮点数计算会存在精度丢失问题(或称舍入误差),其根本原因是二进制和实现位数限制有些数无法有限表示  * 以下...
  • 例如:两浮点数x=0.1101*201,y=(-0.1010)*211,求x+y 一、 对阶 1、求补码 [x]补=00,01;00.1101,[y]补=00,11;11.0110; 2、求阶差 小阶向大阶对阶,同时尾数右移...将对阶后的两个尾数安定点加减运算规则进行运算。 ...
  • 最近看到 0.5+0.1==0.6 输出true 0.1+0.2== 0.3 输出false 很是不解然后就看了下 浮点数储存的问题. 很多博客写的都不怎么好.媒体文章也是晦涩难懂. 有些写的不错但细节很差 我就打算自己写一个, 不废话了 写正文...
  • 如二进制1.0110100111,我们肯定很希望在计算机中有足够的空间,分别存储二进制浮点数的各位与小数点。但由于小数点位置的不确定性,直观的存储方式并不美观,我们采用如下方法存储二进制浮点数: 除0以外的任何...
  • 浮点数加减计算总结

    万次阅读 2016-09-22 15:41:52
    再看告知浮点数的格式,最大值问题: 设浮点数共12位,其中阶码含1位阶符共4位,以2为底,补码表示。尾数含一位数符共8位,补码表示,规格化。该浮点数所能表示的最大正数是?解答:首先,我们马上可以构想出补码...
  • 关于浮点数很多人都知道计算机会丢失精度的问题,那么是精度如何丢失的,为何...其他文章列表如下:有趣的二进制有趣的二进制—高效位运算一、 精度如果你有看过《有趣的二进制》这篇文章,你就会明白进制(不局限于...
  • 一.对运算结果进行规格化处理 (1)先判断结果是不是规格化,如不是执行下面几步....例题分析 例题1: x = 2^11*0.100101, y = 2^-10*(-0.011110)  [x]浮 = 11101,0.100101,[y]浮 = 11110,-0.011110 Ex-Ey =...
  • 浮点数加减运算

    2020-03-09 20:31:46
    浮点数加减运算 1.浮点数的表示: 一般我们表示一个很大的数会用科学计数法,如12 0000 0000 0000 = 1.2x1013。而在计算机中,由于机器字长的限制,我们只能用有限位去近似表示各小数。即M x ra,其中M为尾数,如...
  • 浮点数运算规格化

    千次阅读 多人点赞 2019-12-07 11:14:20
    前言 临近考试,计算机组成原理令人头疼不已,浮点数的运算规格化看书...尾数用双符号位补码表示,经过/运算之后,可能出现以下六种情况,即 ① 00.1 x x … x ② 11.0 x x … x ③ 00.0 x x … x ④ 11.1...
  • 浮点数加减丢失精度原因剖析

    千次阅读 2018-09-20 15:52:41
    这里以1.005为例子,模拟二进制存储 1为整数位 package baseJava; import java.math.BigDecimal; import java.util.HashMap; public class DoubleTest { public static void main(String[] args) { ...
  • 大纲 一、二进制与十进制,八进制,十六进制之间的互换及科学计数法 二、Java标识符的命名规则及...四、浮点数二进制的表示方法(原码、反码,补码,移码及互换) 五、Java运算符、分隔符、转义字符、注释 六、自我介绍
  • 所以我想和大家一起分享定点数和浮点数加减乘除运算的方法,一起在二进制的世界里面遨游吧~ 温馨小贴士,以下内容仅仅包含计算方法(手算和计算机内部表达部分均有),不含运算器数电知识哦。文章以下方思维导图来...
  • 0b二进制 0o八进制 0x十六进制 >>> a = 3/2 >>> a 1.5 >>> 7//2 3 >>> 7%2 1 >>> 2*3 6 >>> 2**3 8 >>> 2**4 16 >>> 2**5 32 >>>...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,738
精华内容 9,495
关键字:

二进制浮点数加减