Math 单个数字(浮点)数据类型的优缺点

Math 单个数字(浮点)数据类型的优缺点,math,floating-point,int,computer-science,precision,Math,Floating Point,Int,Computer Science,Precision,为什么我们在编程语言中使用各种数据类型?为什么不到处使用float呢?我听过一些争论,比如 int上的算术运算速度更快(但为什么?) 存储浮点值需要更多内存。(我明白了。) 使用各种类型的数字数据类型的额外好处是什么 传统上,整数运算速度更快,因为它是一种更简单的运算。它可以在逻辑门中实现,如果设计得当,整个过程可以在一个时钟周期内完成 在大多数现代PC机上,浮点支持实际上相当快,因为花费了大量的时间使其变得更快。它只在低端处理器(如Arduino或某些版本的ARM平台)上使用,浮点运算会受到严

为什么我们在编程语言中使用各种数据类型?为什么不到处使用float呢?我听过一些争论,比如

  • int上的算术运算速度更快(但为什么?)
  • 存储浮点值需要更多内存。(我明白了。)

  • 使用各种类型的数字数据类型的额外好处是什么

    传统上,整数运算速度更快,因为它是一种更简单的运算。它可以在逻辑门中实现,如果设计得当,整个过程可以在一个时钟周期内完成

    在大多数现代PC机上,浮点支持实际上相当快,因为花费了大量的时间使其变得更快。它只在低端处理器(如Arduino或某些版本的ARM平台)上使用,浮点运算会受到严重影响,或者CPU中完全没有浮点运算

    浮点数包含几个不同的数据段:有一个符号位、尾数和指数。要将这三部分放在一起以确定它们所代表的值,您可以执行以下操作:

    value = sign * mantissa * 2^exponent
    
    float i;
    for (i = 1600000; i < 1700000; i += 1);
    
    这比这要复杂一点,因为浮点数优化了尾数的存储方式(例如,尾数的第一位假定为1,因此第一位实际上不需要存储…但这也意味着零必须以特定的方式存储,并且有各种“特殊值”可以存储在“非数字”和无穷大等浮点数中,在使用浮点数时必须正确处理)

    所以要存储数字“3”,尾数为0.75,指数为2。(0.75*2^2=3)

    但要将两个浮点数相加,首先必须将它们对齐。例如,3+10:

    m3 = 0.75  (stored as binary (1)1000000...  the first (1) implicit and not actually stored)
    e3 = 2
    m10 = .625  (stored as binary (1)010000...)
    e10 = 4     (.625 * 2^4 = 10)
    
    你不能把m3和m10加在一起,因为你会得到错误的答案。首先必须将m3移位几位,以使e3和e10匹配,然后可以将尾数相加,并将结果重新组合为新的浮点数。当然,一个具有良好浮点实现的CPU可以为您完成所有这些,而且速度很快

    那么,为什么您不想对所有内容都使用浮点值呢?首先,有一个精确性的问题。如果将两个整数相加或相乘得到另一个整数,只要不超过整数大小的限制,得到的答案将完全正确。浮点不是这样的。例如:

    x = 1000000000.0
    y = .0000000001
    for (cc = 0; cc < 1000000000; cc++) { x += y; }
    
    x = 11.0 / 500
    if (x * 50 == 1.1) { ...  It doesn't!
    
    for (float x = 0.0; x < 1.0; x += 0.01) { print x; }
    // prints 101 values instead of 100, the last one being 0.9999999...
    
    如果你把(y)加起来100亿倍,误差也会放大100亿倍,所以最后的误差大约是10^-16

    一个好的浮点实现会尽量减少这些错误,但并不总是正确的。这个问题是如何存储数字的基础,在某种程度上是不可避免的。因此,例如,尽管将货币值存储在浮点中似乎很自然,但最好将其存储为整数,以确保该值始终是精确的

    “精确性”问题还意味着,当您测试浮点数的值时,一般来说,您不能使用精确比较。例如:

    x = 1000000000.0
    y = .0000000001
    for (cc = 0; cc < 1000000000; cc++) { x += y; }
    
    x = 11.0 / 500
    if (x * 50 == 1.1) { ...  It doesn't!
    
    for (float x = 0.0; x < 1.0; x += 0.01) { print x; }
    // prints 101 values instead of 100, the last one being 0.9999999...
    
    x=11.0/500
    如果(x*50==1.1){…它不会!
    对于(float x=0.0;x<1.0;x+=0.01){print x;}
    //打印101个值而不是100个,最后一个值是0.9999999。。。
    
    测试失败,因为(x)不完全是我们指定的值,而1.1编码为浮点时也不完全是我们指定的值。它们都很接近,但不精确。因此,您必须进行不精确的比较:

    if (abs(x - expected_value) < small_value) {...
    
    if(abs(x-期望值)
    选择正确的“小价值”本身就是一个问题。它取决于你对这些价值观做了什么,你试图实现什么样的行为

    最后,如果你看一下“需要更多内存”的问题,你也可以把它扭转过来,从你使用的内存中得到的东西来考虑

    如果您可以使用整数数学解决您的问题,则32位无符号整数允许您使用介于0到40亿之间的(精确)值

    如果使用32位浮点而不是32位整数,则可以存储大于40亿的值,但仍然受到表示形式的限制:在这32位中,1位用于符号位,8位用于尾数,因此尾数为23位(有效为24位)。一旦(x>=2^24),就超出了存储整数的范围在那个浮点数中“正好”,所以(x+1=x)。这样的循环:

    value = sign * mantissa * 2^exponent
    
    float i;
    for (i = 1600000; i < 1700000; i += 1);
    
    float i;
    对于(i=1600000;i<1700000;i+=1);
    

    永远不会终止:(i)将达到(2^24=16777216),其尾数的最低有效位的大小将大于1,因此将(i)加1将不再有任何影响。

    传统上,整数运算速度更快,因为它是一种更简单的运算。它可以在逻辑门中实现,如果设计得当,整个过程可以在一个时钟周期内完成

    在大多数现代PC机上,浮点支持实际上相当快,因为已经投入了大量的时间来提高它的速度。只有在低端处理器(如Arduino或某些版本的ARM平台)上,浮点受到严重影响,或者CPU完全没有浮点支持

    浮点数包含几个不同的数据段:有一个符号位、尾数和指数。要将这三部分放在一起确定它们所表示的值,请执行以下操作:

    value = sign * mantissa * 2^exponent
    
    float i;
    for (i = 1600000; i < 1700000; i += 1);
    
    这比这要复杂一点,因为浮点数优化了尾数的存储方式(例如,尾数的第一位假定为1,因此第一位实际上不需要存储…但这也意味着零必须以特定的方式存储,并且有各种“特殊值”可以存储在浮点数中,比如“不是数字”和i