当我编译这个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?
有任何想法让我在入睡前感觉不那么愚蠢吗?
答案 0 :(得分:4)
long double
无法准确表示大多数值,通常是在讨论大值(std::numeric_limits<float>::max()
),因此完全值之间存在较大差距long double
。
检查long double
1.0
,1.0
与long double
可以代表的ldMinFloat
之间的最小值之间的差异。
如果要查找long double
可以存储的ldMinFloat
以下std::abs(ldMinFloat) * std::numeric_limits<long double>::epsilon()
的最大值与36893485948395847680
之间的差异,可以使用以下近似值 :
long double
这是(在我的计算机上)340282346638528859811704183484516925440
,因此340282346638528859811704183484516925440 +/- 36893485948395847680
无法区分float
和double
(大约...)之间的值,即使它可以存储值远低于此。
下一个表示值的更精确计算:
假设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 都是相同的,因此(V2
是V2 - V1 = 2 ^ (E - shift) * M2 - 2 ^ (E - shift) * M1
= 2 ^ (E - shift) * (M2 - M1)
而E
是下一个可表示的价值,我假设这个正值,这里的标志无关紧要):
1050
上面(10001111110
)中的 double
为1023
,64位E - shift = 127
的移位为V2 - V1 = 2 ^ 127 * (M2 - M1)
,因此M1
:
ldMinFloat
这里我们“幸运”,因为0
(M1
的尾数)中的最后一位是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()
}
}
}
尾数可以传播余数甚至改变指数,因此计算会更难。