首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从long long到float的隐式转换产生意外结果

从long long到float的隐式转换产生意外结果
EN

Stack Overflow用户
提问于 2017-01-04 10:32:15
回答 2查看 196关注 0票数 7

为了(使用VS2012)验证一本书的主张(第二句),

代码语言:javascript
运行
复制
When we assign an integral value to an object of floating-point type, the fractional part is zero. 
Precision may be lost if the integer has more bits than the floating-point object can accommodate.

我写了以下小程序:

代码语言:javascript
运行
复制
#include <iostream>
#include <iomanip>

using std::cout;
using std::setprecision;

int main()
{
    long long i = 4611686018427387905; // 2^62 + 2^0

    float f = i; 

    std::streamsize prec = cout.precision();

    cout << i << " " << setprecision(20) << f << setprecision(prec) << std::endl;

    return 0;
}

输出为

代码语言:javascript
运行
复制
4611686018427387905 4611686018427387900

我期望表单的输出

代码语言:javascript
运行
复制
4611686018427387905 4611690000000000000

一个4字节的浮点型如何能够保留这么多关于8字节整数的信息?是否有i的值可以实际证明这一主张?

EN

回答 2

Stack Overflow用户

发布于 2017-01-04 10:41:25

浮点数不会将数据存储在基数10中,而是存储在基数2中。因此,4611690000000000000实际上不是一个非常舍入的数字。它的二进制表示是:

代码语言:javascript
运行
复制
100000000000000000000111001111100001000001110001010000000000000. 

正如您所看到的,这将需要大量数据才能准确记录。然而,实际打印的数字具有以下二进制表示形式:

代码语言:javascript
运行
复制
11111111111111111111111111111111111111111111111111111111111100

正如您所看到的,这是一个非常四舍五入的数字,事实是它从2的幂中减去了4,这很可能是由于转换为基数10的算法中的舍入。

作为一个无法正确放入浮点数的数字的示例,请尝试您期望的数字:

代码语言:javascript
运行
复制
4611690000000000000

你会注意到,这将是非常不同的结果。

票数 5
EN

Stack Overflow用户

发布于 2017-01-04 10:42:06

浮点数保留了如此多的信息,因为您正在处理的数字非常接近2的幂。

float格式以基本的二进制科学记数法存储数字。在您的例子中,它被存储为类似于

1.0000000...61个零...00000001* 2^62。

float格式不能存储62位小数,因此最后的1被截断...但是我们还剩下2^62,这几乎完全等于您试图存储的数字。

我不擅长制造示例,但CERT并非如此;您可以查看一个错误的数字转换here的示例。注意,示例是用Java语言编写的,但是C++使用相同的浮点类型;另外,第一个示例是4字节int和4字节float之间的转换,但这进一步证明了您的观点(需要存储的整数信息比示例中的少,但仍然失败)。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41455327

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档