gpt4 book ai didi

C++11 numeric_limits 和算术

转载 作者:行者123 更新时间:2023-11-30 01:42:51 25 4
gpt4 key购买 nike

当我编译这段 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

谁能解释一下为什么减法不是-340282346638528859811704183484516925450.000000???

基于此link long double max 值为 +/- 1.797,693,134,862,315,7*10^308 我真的不明白为什么尾数会在基本整数算术中解释这种行为?或者它是从 float 到 long double 的隐式转换?还是 std::cout 的运算符 <<?

有什么办法可以帮助我在 sleep 前感觉不那么愚蠢吗?

最佳答案

A long double不能准确表示大多数值,通常您谈论的是大值 ( std::numeric_limits<float>::max() ),因此 完全long double 表示的值之间存在很大差距.

检查 epsilon 对于 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 (大约......)即使它可以存储远低于此的值。


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

假设 32 位 float和 64 位 double (我没有 96 位 long double 来测试...)并且都使用 IEEE 754 表示:

最低的 float ( -340282346638528859811704183484516925440) 具有以下二进制表示形式:

1 11111110 11111111111111111111111

转换为 double :

1 10001111110 1111111111111111111111100000000000000000000000000000

低于这个数的第一个可表示的数字是(只需将尾数加 1,幸运的是这个数字很容易):

1 10001111110 1111111111111111111111100000000000000000000000000001

这正是 -340282346638528897590636046441678635008 .两个值之间的差异(在代码中计算)是:

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

如何计算与 ldMinFloat 的差异?

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

V = 2 ^ (E - shift) * M

在这里,指数 E对于两个值1 都是相同的,所以(V1ldMinFloatV2 是下一个可表示的值,我为此假设正值,这里的符号无关紧要):

V2 - V1 = 2 ^ (E - shift) * M2 - 2 ^ (E - shift) * M1
= 2 ^ (E - shift) * (M2 - M1)

E1050在上面 ( 10001111110 ) 和 64 位的移位 double1023 , 所以 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

1 这一切都顺利进行,因为 ldMinFloat 中尾数的最后一位是0 , 如果不是这样,添加 1到这个尾数可以传播余数甚至改变指数,所以计算会更难。

关于C++11 numeric_limits<float> 和算术,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38740250/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com