C ++ 11 numeric_limits <float>和算术

时间:2016-08-03 09:55:16

标签: c++ c++11

当我编译这个C ++代码时,我并不期望看到这个输出

#include <iostream>
#include <iomanip>
#include <limits>

int main() {
    const long double ldMinFloat = std::numeric_limits<float>::lowest();
    std::cout << std::left << std::setw(20) << "ldMinFloat" << "= " << std::fixed << ldMinFloat << std::endl;
    std::cout << std::left << std::setw(20) << "(ldMinFloat - 10)" << "= " << std::fixed << (ldMinFloat - 10) << std::endl;
return 0;
    return 0;
}

这是输出

ldMinFloat          = -340282346638528859811704183484516925440.000000
(ldMinFloat - 10)   = -340282346638528859811704183484516925440.000000

有人能够解释为什么减法不是-3402823466385288598117041834845169254 50 .000000 ???

基于这个link长的双倍最大值是+/- 1.797,693,134,862,315,7 * 10 ^ 308,我真的不明白为什么尾数会在基本整数算术中解释这种行为?或者是从float到long double的隐式转换?或者它是运营商&lt;&lt; std :: cout?

有任何想法让我在入睡前感觉不那么愚蠢吗?

1 个答案:

答案 0 :(得分:4)

long double无法准确表示大多数值,通常是在讨论大值(std::numeric_limits<float>::max()),因此完全值之间存在较大差距long double

检查long double 1.01.0long double可以代表的ldMinFloat之间的最小值之间的差异。

如果要查找long double可以存储的ldMinFloat以下std::abs(ldMinFloat) * std::numeric_limits<long double>::epsilon() 的最大值与36893485948395847680之间的差异,可以使用以下近似值

long double

这是(在我的计算机上)340282346638528859811704183484516925440,因此340282346638528859811704183484516925440 +/- 36893485948395847680无法区分floatdouble(大约...)之间的值,即使它可以存储值远低于此。

下一个表示值的更精确计算:

假设32位long double和64位-340282346638528859811704183484516925440(我没有96位1 11111110 11111111111111111111111 来测试......)并且两者都使用IEEE 754表示:

最低浮点数(double)具有以下二进制表示形式:

1 10001111110 1111111111111111111111100000000000000000000000000000

转换为1 10001111110 1111111111111111111111100000000000000000000000000001

-340282346638528897590636046441678635008

低于此值的双倍的第一个可表示的数字是(只是在尾数上加1,幸运的是这个数字很容易):

37778931862957161709568 // About half the value of the approximation (using double)

究竟是ldMinFloat。两个值之间的差异(在代码中计算)是:

V = 2 ^ (E - shift) * M

如何从E计算这种差异?

您可以使用二进制表示来计算此差异。您知道,对于IEEE754,“转换”是(无符号):

V1

此处,指数ldMinFloat对于值 1 都是相同的,因此(V2V2 - V1 = 2 ^ (E - shift) * M2 - 2 ^ (E - shift) * M1 = 2 ^ (E - shift) * (M2 - M1) E是下一个可表示的价值,我假设这个正值,这里的标志无关紧要):

1050
上面(10001111110)中的

double1023,64位E - shift = 127的移位为V2 - V1 = 2 ^ 127 * (M2 - M1) ,因此M1

ldMinFloat

这里我们“幸运”,因为0M1的尾数)中的最后一位是M2,因此M2 - M1 = 0.000...001b // <-------> 52 bits (51 zeros) V2 - V1 = (2 ^ 127) * 0.000...001b = (2 ^ 127) >> 52 = 37778931862957161709568 之间的差异是:

ldMinFloat

所以区别在于:

0

1 这一切都顺利进行,因为1中尾数的最后一位是SELECT Count(*) as OptIn, Month(StartDate) As MonthNum, Year(StartDate) As YearNum FROM ( select PersonID, min(startdate) as startdate FROM [dietdb].[dbo].[PaymentsTBL] group by PersonID ) as t group by Month(StartDate), Year(StartDate) ,如果不是这样,则向此添加let dynamicBehaviour = UIDynamicItemBehavior(items: [randomWord]) weak var weakBehaviour = dynamicBehaviour weak var weakSelf = self dynamicBehaviour.action = { if let currentY = weakBehaviour?.linearVelocityForItem(rndWord).y { if currentY > CGRectGetMaxY(self.view.frame) / 2 { weakSelf?.animator?.removeAllBehaviors() weakSelf?.randomWord?.removeFromSuperview() } } } 尾数可以传播余数甚至改变指数,因此计算会更难。