首页 > 其他分享 >3.14 + 1e10 - 1e10 = 0 ? ——浮点数的本质

3.14 + 1e10 - 1e10 = 0 ? ——浮点数的本质

时间:2023-08-27 21:22:04浏览次数:42  
标签:阶码 尾数 浮点数 3.14 1e10 times

3.14 + 1e10 - 1e10 = 0 ? ——浮点数的本质

我们先看这样一个例子:

#include <iostream>

int main(int argc, char **argv)
{   
    
    float a = 3.14;
    float b = 1e10;

    std::cout <<  a << "   " <<  b << std::endl;
    std::cout <<  (a+b)-b << std::endl;
    std::cout <<  a+(b-b) << std::endl;

	return 0;
}

这个程序的输出是:

image-20230827201005581

我们可以看到 (a+b)-b 得到了0,这个结果是有些匪夷所思的。为了解答这个问题,我们需要理解浮点数在计算机中的表示方法。

浮点数的表示——IEEE754

IEEE浮点标准使用\(V = (-1)^s \times M \times 2^E\)来表示一个数,其中\(s\)是一个符号位,取0或者1,用来确定实数的符号,\(M\)是尾数,\(E\)是阶码,通常用移码表示。

对于单精度浮点数,符号位为1位,阶码为8位,尾数为23位。对于双精度浮点数,符号位为1位,阶码为11位,尾数为52位。

举个例子,对于一个实数0.675,其二进制表示为0.101,我们可以看做\((-1)^0 \times 1.01 \times 2^{-1}\),因此阶码\(E\)的移码表示是10000000,对于尾数,暗含一个1,因此对于尾数的表示是01000000000000000000000,空余位补0,综上可以得到0.625的单精度浮点数表示:

image-20230827203322625

这里帮大家回顾一下浮点数的表示,更多细节可以查阅相关资料。

现在我们就可以回答上面的问题了:

\[1e10 = 10000000000 = 1001010100000010111110010000000000_2 = 1.001010100000010111110010000000000_2 \times 2^{33} \]

此时1e10二进制表示的尾数部分是高于23位的,因此会执行舍入操作,因此尾数\(M\)=00101010000001011111001

综上,1e10的单精度浮点数表示是: 0 101000 00101010000001011111001

而对于3.14则有:\(3.14 \approx 11.0010001111010111000010100011110_2 =1.10010001111010111000010100011110_2 \times 2^1\)

为了实现3.14+1e20,我们需要调整3.14的阶码,使得二者的阶码相同

因此此时有:

\[3.14 \approx \\ 0.00000000000000000000000000000000110010001111010111000010100011110_2 \times 2^{33} \]

二者相加有,\(3.14+1e20 = 1.00101010000001011111001(截断)000000000110010001111010111000010100011110_2 \times 2^{33}\)

由于单精度浮点数尾数只有23位,因此会进行舍入操作,这里是截断23位之后的二进制数字,最终3.14+1e10与1e10的二进制代码相同

所以(3.14 + 1e10) -1e10 = 0

扩展

  1. 回到最开始的代码,如果将a,b修改为double类型,得到的结果是不是会有变化呢?

​ 答案是会的,因此double的尾数是52位,因此尾数并不会发生舍入,所以此时的结果是正确的。

  1. 我们可以发现,当浮点数a >> b时,由于需要调整b的阶码与a对齐,所以a的尾数表示左侧可能会出现大量的0,导致b的有效位被截断而丢失。

标签:阶码,尾数,浮点数,3.14,1e10,times
From: https://www.cnblogs.com/programmerwang/p/17660871.html

相关文章

  • 浮点数在内存中的存储形式
       大家都知道浮点数是什么,那他在内存中是怎么存储的呢?根据国际标准IEEE754规定中,任意一个二进制浮点数v可以表示成下面的形式:(-1)S*M*2E(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。M表示有效数字,大于等于1,小于2.2^E表示指数位。   那怎么来理解这段话呢,我们举个例......
  • 5.9 汇编语言:浮点数操作指令
    汇编语言是一种面向机器的低级语言,用于编写计算机程序。汇编语言与计算机机器语言非常接近,汇编语言程序可以使用符号、助记符等来代替机器语言的二进制码,但最终会被汇编器编译成计算机可执行的机器码。浮点运算单元是从80486处理器开始才被集成到CPU中的,该运算单元被称为FPU浮点......
  • golang之浮点数处理库decimal
    decimal库包是用来解决float类型对象之间运算不准确的问题的。所以,如果你想使用decimal库包,你必须先把float类型对象通过decimal.NewFromFloat()函数转成decimal.Decimal类型,然后再计算,最后还得再转成你所需要的类型。范例:packagemainimport"log"funcmain(){a:=......
  • Python教程(6)——Python变量的基础类型。|整数类型|浮点数类型|字符串类型|布尔类型|
    学习编程语言,不得不忽视变量这个概念。Python中的变量是用于存储数据的名称,你可以将值赋给变量,并在程序的其他地方使用该变量来引用该值。变量在程序中起到存储和操作数据的作用。如果学过C/C++语言的同学,定义了变量后,需要加个类型的限制,比如intage=28doublemoney=10.2......
  • C# 使用SIMD向量类型加速浮点数组求和运算(4):用引用代替指针, 摆脱unsafe关键字,兼谈Unsa
    作者:zyl910目录一、引言二、办法说明2.1历史2.2局部引用变量与引用所指的值(类似指针的地址运算符&、间接运算符*)2.3重新分配局部引用变量(类似指针直接赋值)2.4引用地址调整(类似指针加减法)2.5引用地址比较(类似指针比较)2.6重新解释(类似C++的reinterpret_cast)2.7引用取消只......
  • 浮点数
    1、介绍一般,在计算机中的整数数值可以基于补码规则进行表示为比特,而小数择是基于浮点数规则表示为比特。浮点数规则,本质上是科学计数法的思想,将十进制小数转为二进制数,对一组连续比特位划分,分别表示该二进制数的符号位、指数和底数信息。注意,在固定长度的比特位中,符号位一般不变,......
  • PHP浮点数运算的问题
    $a=0.1;$b=0.7;$c=0.5;$d=0.9;if($a+$b==0.8){echo'==';}else{echo'!=';}//!=if($a+$c==0.6){echo'==';}else{echo'!=';}//==if($a+$d==1){echo'==';}else{echo'!=';......
  • 75.怎样判断两个浮点数是否相等?
    75.怎样判断两个浮点数是否相等?对两个浮点数判断大小和是否相等不能直接用==来判断,会出错!明明相等的两个数比较反而是不相等!对于两个浮点数比较只能通过相减并与预先设定的精度比较,记得要取绝对值!浮点数与0的比较也应该注意。与浮点数的表示方式有关。参考资料来源:阿秀......
  • 浮点数二分模板
    题目给定一个浮点数$n$,求它的三次方根。输入格式共一行,包含一个浮点数$n$。输出格式共一行,包含一个浮点数,表示问题的解。注意,结果保留$6$位小数。数据范围$−10000≤n≤10000$输入样例:$1000.00$输出样例:$10.000000$思路浮点数二分可以直接分,无需考虑边界情况......
  • 浮点数-Float-Double转二进制在线工具
    浮点数-Float-Double转二进制Float转二进制,Double转浮点数-Float-Double转二进制https://tooltt.com/floatconverter/在线单双精度(Float,Double)浮点数转二进制浮点数,是属于有理数中某特定子集的数的数字表示,在计算机中用以近似表示任意某个实数。具体的说,这个实数由一......